diff --git a/toolchain/check/context.h b/toolchain/check/context.h index 4e034df256b0..8c693dd01dfc 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -278,6 +278,8 @@ class Context { SemIR::ConstantId facet_type_const_id; }; llvm::SmallVector impls; + + SemIR::LocId loc_id; }; auto where_stack() -> llvm::SmallVector& { diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index 4c10e1ff61c4..9391f5424661 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -3243,6 +3243,10 @@ auto TryEvalTypedInst(EvalContext& eval_context, Phase phase = Phase::Concrete; SemIR::FacetTypeInfo info; + if (inst.type_id() == SemIR::ErrorInst::TypeId) { + return SemIR::ErrorInst::ConstantId; + } + // Note that these requirement instructions don't have a constant value. That // means we have to look for errors inside them, we can't just look to see if // their constant value is an error. diff --git a/toolchain/check/handle_where.cpp b/toolchain/check/handle_where.cpp index 8be89bb1cb9d..c9d10ab9bb81 100644 --- a/toolchain/check/handle_where.cpp +++ b/toolchain/check/handle_where.cpp @@ -98,7 +98,7 @@ auto HandleParseNode(Context& context, Parse::WhereOperandId node_id) -> bool { // Add a context stack for tracking constraints, that will be used to allow // later constraints to read from them eagerly. - context.where_stack().emplace_back(); + context.where_stack().push_back({.loc_id = node_id}); // Make rewrite constraints from the self facet type available immediately to // expressions in rewrite constraints for this `where` expression. @@ -339,12 +339,6 @@ auto HandleParseNode(Context& context, Parse::RequirementImplsId node_id) // TODO: For things like `HashSet(.T) as type`, add an implied constraint // that `.T impls Hash`. - if (FindAndDiagnoseAmbiguousPeriodSelf(context, lhs_as_type.inst_id, - rhs_id)) { - rhs_as_type.type_id = SemIR::ErrorInst::TypeId; - rhs_as_type.inst_id = SemIR::ErrorInst::TypeInstId; - } - // Build up the list of arguments for the `WhereExpr` inst. context.args_type_info_stack().AddInstId( AddInstInNoBlock( @@ -387,6 +381,23 @@ auto HandleParseNode(Context& /*context*/, Parse::RequirementAndId /*node_id*/) return true; } +// There are two ways to nest `where` expressions, this diagnoses a `where` +// expression inside the RHS of another `where` expression. +// +// Whereas it is valid to nest a `where` expression on the LHS of another +// `where` expression. +static auto DiagnoseNestedWhere(Context& context, SemIR::LocId loc_id, + SemIR::LocId outer_loc_id) -> void { + CARBON_DIAGNOSTIC( + NestedWhereInsideWhere, Error, + "found `where` expression nested on the right-hand side of `where`"); + auto builder = context.emitter().Build(loc_id, NestedWhereInsideWhere); + CARBON_DIAGNOSTIC(NestedWhereInsideWhereOuterNote, Note, + "on right-hand side of `where` here"); + builder.Note(outer_loc_id, NestedWhereInsideWhereOuterNote); + builder.Emit(); +} + auto HandleParseNode(Context& context, Parse::WhereExprId node_id) -> bool { context.where_stack().pop_back(); // Remove `PeriodSelf` from name lookup, undoing the `Push` done for the @@ -394,9 +405,17 @@ auto HandleParseNode(Context& context, Parse::WhereExprId node_id) -> bool { context.scope_stack().Pop(/*check_unused=*/true); SemIR::InstBlockId requirements_id = context.args_type_info_stack().Pop(); + auto type_id = SemIR::TypeType::TypeId; + if (!context.where_stack().empty()) { + DiagnoseNestedWhere(context, node_id, context.where_stack().back().loc_id); + type_id = SemIR::ErrorInst::TypeId; + } + + // TODO: Look at the constant value and diagnose NestedWhereInsideWhere if + // there are any non-extend constraints present. AddInstAndPush( context, node_id, - {.type_id = SemIR::TypeType::TypeId, .requirements_id = requirements_id}); + {.type_id = type_id, .requirements_id = requirements_id}); return true; } diff --git a/toolchain/check/period_self.cpp b/toolchain/check/period_self.cpp index 5987fc12fbe9..8ffc228f8c5c 100644 --- a/toolchain/check/period_self.cpp +++ b/toolchain/check/period_self.cpp @@ -491,320 +491,4 @@ auto IsPeriodSelf(Context& context, SemIR::InstId inst_id, bool canonicalize) return false; } -class SearchNonCanonicalForExplicitPeriodSelf : public SubstInstCallbacks { - public: - explicit SearchNonCanonicalForExplicitPeriodSelf(Context* context, - SemIR::LocId* found) - : SubstInstCallbacks(context), found_(found) {} - - auto Subst(SemIR::InstId& inst_id) -> SubstResult override { - if (found_->has_value()) { - return FullySubstituted; - } - - auto const_inst_id = context().constant_values().GetConstantInstId(inst_id); - if (const_inst_id == SemIR::TypeType::TypeInstId) { - // Recursion base case. TypeType has type TypeType. - return FullySubstituted; - } - if (context().insts().Is(const_inst_id)) { - // Don't look for `.Self` in nested facet types, they aren't replaced - // with a facet value and just remain as abstract. WhereExprs evaluate - // to a FacetType but are handled outside of Subst. - return FullySubstituted; - } - - if (auto name_ref = context().insts().TryGetAs(inst_id)) { - // Canonicalization not necessary; NameRef contains the SymbolicBinding - // directly, not an `as type` conversion. - if (IsPeriodSelf(context(), name_ref->value_id, - /*canonicalize=*/false)) { - // `.Self` does not have a location, the NameRef pointing to it does. - *found_ = SemIR::LocId(inst_id); - return FullySubstituted; - } - } - - return SubstOperands; - } - - auto Rebuild(SemIR::InstId /*orig_inst_id*/, SemIR::Inst /*new_inst*/) - -> SemIR::InstId override { - CARBON_FATAL(); - } - - private: - SemIR::LocId* found_; -}; - -class SearchCanonicalForExplicitPeriodSelf : public SubstInstCallbacks { - public: - explicit SearchCanonicalForExplicitPeriodSelf(Context* context, bool* found) - : SubstInstCallbacks(context), found_(found) {} - - auto Subst(SemIR::InstId& inst_id) -> SubstResult override { - if (*found_) { - return FullySubstituted; - } - - auto const_inst_id = context().constant_values().GetConstantInstId(inst_id); - if (const_inst_id == SemIR::TypeType::TypeInstId) { - // Recursion base case. TypeType has type TypeType. - return FullySubstituted; - } - if (context().insts().Is(const_inst_id)) { - // Don't look for `.Self` in nested facet types, they aren't replaced - // with a facet value and just remain as abstract. WhereExprs evaluate - // to a FacetType but are handled outside of Subst. - return FullySubstituted; - } - - if (auto access = context().insts().TryGetAs( - const_inst_id)) { - if (auto lookup = context().insts().TryGetAs( - access->witness_id)) { - // Canonicalization not necessary; we are working with the constant - // value already, and the query self in a witness is already - // canonicalized. - if (IsPeriodSelf(context(), lookup->query_self_inst_id, - /*canonicalize=*/false)) { - // An implicit `.Self` in a member designator is always allowed. - return FullySubstituted; - } - } - } - - // Canonicalization not necessary; Subst will recurse anyway, so avoid - // extra work for non-matches. - if (IsPeriodSelf(context(), const_inst_id, /*canonicalize=*/false)) { - *found_ = true; - return FullySubstituted; - } - - return SubstOperands; - } - - auto Rebuild(SemIR::InstId /*orig_inst_id*/, SemIR::Inst /*new_inst*/) - -> SemIR::InstId override { - CARBON_FATAL(); - } - - private: - bool* found_; -}; - -static auto ReportAmbiguousPeriodSelf(Context& context, SemIR::LocId loc_id) - -> void { - CARBON_DIAGNOSTIC(AmbiguousPeriodSelf, Error, - "`.Self` is ambiguous after nested `where` in ` " - "impls ...` clause."); - context.emitter().Emit(loc_id, AmbiguousPeriodSelf); -} - -// Searches a type for a reference to `.Self`. Types are canonical, so they -// only contain canonical values/inststructions, which have no location of -// their own. -// -// The search excludes ImplWitnessAccess into `.Self`, which represents a -// designator like `.X`. -// -// The search does not recurse into FacetTypes, as some can include valid -// references to the top level `.Self`, or abstract `.Self` references that -// are not replaced. FacetTypes are handled by the higher level search. -// -// Returns true if found, and diagnosed. -static auto SearchTypeForPeriodSelf(Context& context, SemIR::LocId loc_id, - SemIR::TypeId type_id) -> bool { - bool found_canonical = false; - SearchCanonicalForExplicitPeriodSelf callbacks(&context, &found_canonical); - - auto canonical_inst_id = context.types().GetTypeInstId(type_id); - SubstInst(context, canonical_inst_id, callbacks); - - // The type has no locations internally, as it stores canonical - // instructions. If we find any `.Self` reference, we report the entire - // type. - if (found_canonical) { - ReportAmbiguousPeriodSelf(context, loc_id); - return true; - } - return false; -} - -// Searches a facet type for a reference to `.Self`. FacetTypes are canonical, -// so they only contain canonical values/inststructions, which have no -// location of their own. -// -// The search excludes ImplWitnessAccess into `.Self`, which represents a -// designator like `.X`. -// -// Returns true if found, and diagnosed. -static auto SearchFacetTypeForPeriodSelf(Context& context, SemIR::LocId loc_id, - SemIR::FacetTypeId facet_type_id) - -> bool { - bool found_canonical = false; - SearchCanonicalForExplicitPeriodSelf callbacks(&context, &found_canonical); - - const auto& info = context.facet_types().Get(facet_type_id); - // The LHS of a `WhereExpr` only has extend constraints. - for (auto extend : info.extend_constraints) { - auto block_id = context.specifics().GetArgsOrEmpty(extend.specific_id); - for (auto inst_id : context.inst_blocks().GetOrEmpty(block_id)) { - SubstInst(context, inst_id, callbacks); - } - } - for (auto extend : info.extend_named_constraints) { - auto block_id = context.specifics().GetArgsOrEmpty(extend.specific_id); - for (auto inst_id : context.inst_blocks().GetOrEmpty(block_id)) { - SubstInst(context, inst_id, callbacks); - } - } - // The facet type has no locations internally, as it stores canonical - // instructions. If we find any `.Self` reference, we report the entire - // facet type. - if (found_canonical) { - ReportAmbiguousPeriodSelf(context, loc_id); - return true; - } - return false; -} - -// Searches a non-canonical instruction for an explicitly written use of -// `.Self`, which is represented as a NameRef instruction. -// -// Returns true if found, and diagnosed. -static auto SearchNonCanonicalInstForPeriodSelf(Context& context, - SemIR::InstId inst_id) -> bool { - auto found = SemIR::LocId::None; - SearchNonCanonicalForExplicitPeriodSelf callbacks(&context, &found); - SubstInst(context, inst_id, callbacks); - if (found.has_value()) { - ReportAmbiguousPeriodSelf(context, found); - return true; - } - return false; -} - -auto FindAndDiagnoseAmbiguousPeriodSelf(Context& context, - SemIR::InstId impls_lhs_id, - SemIR::InstId impls_rhs_id) -> bool { - // Look for errors up front. We don't need to look for them in the rest of - // the function. - if (context.constant_values().Get(impls_lhs_id) == - SemIR::ErrorInst::ConstantId || - context.constant_values().Get(impls_rhs_id) == - SemIR::ErrorInst::ConstantId) { - return false; - } - - if (IsPeriodSelf(context, impls_lhs_id)) { - // `.Self impls X where ...` does not restrict any use of `.Self` on the - // RHS of the `where` since the `.Self` on the LHS of `where` did not - // introduce any ambiguity. A `.Self` on the RHS of the `where` applies to - // the same thing as on the LHS of the `impls`. - return false; - } - - struct WorkItem { - SemIR::WhereExpr where_expr; - bool search_lhs; - }; - - llvm::SmallVector work; - if (auto where_expr = - context.insts().TryGetAs(impls_rhs_id)) { - work.push_back({.where_expr = *where_expr, .search_lhs = false}); - } - - while (!work.empty()) { - auto work_item = work.pop_back_val(); - - // Look in the non-canonical WhereExpr for explicit references to `.Self`, - // which will be considered as ambiguous. - for (auto inst_id : context.inst_blocks().GetOrEmpty( - work_item.where_expr.requirements_id)) { - auto inst = context.insts().Get(inst_id); - CARBON_KIND_SWITCH(inst) { - case CARBON_KIND(SemIR::RequirementBaseFacetType base): { - if (work_item.search_lhs) { - // If the base type is more than a reference to an interface or - // constraint, such as having specific arguments, it will be a - // FacetType instruction. - if (auto facet_type = context.insts().TryGetAs( - base.base_type_inst_id)) { - if (SearchFacetTypeForPeriodSelf( - context, SemIR::LocId(base.base_type_inst_id), - facet_type->facet_type_id)) { - return true; - } - } - } - break; - } - case CARBON_KIND(SemIR::RequirementRewrite rewrite): { - if (SearchNonCanonicalInstForPeriodSelf(context, rewrite.lhs_id)) { - return true; - } - if (SearchNonCanonicalInstForPeriodSelf(context, rewrite.rhs_id)) { - return true; - } - break; - } - case CARBON_KIND(SemIR::RequirementEquivalent equiv): { - if (SearchNonCanonicalInstForPeriodSelf(context, equiv.lhs_id)) { - return true; - } - if (SearchNonCanonicalInstForPeriodSelf(context, equiv.rhs_id)) { - return true; - } - break; - } - case CARBON_KIND(SemIR::RequirementImpls impls): { - if (!IsPeriodSelf(context, impls.lhs_id)) { - if (SearchTypeForPeriodSelf( - context, SemIR::LocId(impls.lhs_id), - context.types().GetTypeIdForTypeInstId(impls.lhs_id))) { - return true; - } - } - - CARBON_KIND_SWITCH(context.insts().Get(impls.rhs_id)) { - case CARBON_KIND(SemIR::FacetType facet_type): { - // If the RHS of the `impls` is a complex facet type (such as - // when it has specific arguments) but has no `where`, then it - // will be a FacetType instruction. - if (SearchFacetTypeForPeriodSelf(context, - SemIR::LocId(impls.rhs_id), - facet_type.facet_type_id)) { - return true; - } - break; - } - case CARBON_KIND(SemIR::WhereExpr rhs_where_expr): { - // If the RHS of the `impls` contains a `where`, then it will be - // a WhereExpr instruction. - work.push_back( - {.where_expr = rhs_where_expr, .search_lhs = true}); - break; - } - default: - // Otherwise, it's a simple facet type, which is just a - // reference to an interface or constraint. There's nowhere to - // look for a - // `.Self`. - break; - } - - break; - } - default: - CARBON_FATAL("unexpected inst {0} in WhereExpr requirements block", - inst); - } - } - } - - return false; -} - } // namespace Carbon::Check diff --git a/toolchain/check/period_self.h b/toolchain/check/period_self.h index e66fef019bc2..57c2ea3f3ee9 100644 --- a/toolchain/check/period_self.h +++ b/toolchain/check/period_self.h @@ -85,21 +85,6 @@ auto SubstPeriodSelfInFacetType(Context& context, SemIR::LocId loc_id, auto IsPeriodSelf(Context& context, SemIR::InstId inst_id, bool canonicalize = true) -> bool; -// Look for ambiguous `.Self` in a `T impls X where ...` statement. The given -// inst ids are the non-canonical insts for the LHS and RHS of the `impls` -// inside a `where` expression. -// -// If the LHS is not `.Self` and RHS contains a nested `where` expression, the -// value of `.Self` becomes ambiguous on the RHS of the `where` (it could mean -// either the original value or new value given by the LHS of the `impls`). Note -// that implicit `.Self` references are never ambiguous, they always refer to -// the innermost value that `.Self` could refer to. -// -// Returns true if an error was diagnosed. -auto FindAndDiagnoseAmbiguousPeriodSelf(Context& context, - SemIR::InstId impls_lhs_id, - SemIR::InstId impls_rhs_id) -> bool; - } // namespace Carbon::Check #endif // CARBON_TOOLCHAIN_CHECK_PERIOD_SELF_H_ diff --git a/toolchain/check/testdata/facet/access.carbon b/toolchain/check/testdata/facet/access.carbon index 14350ef27b9a..074a1d695985 100644 --- a/toolchain/check/testdata/facet/access.carbon +++ b/toolchain/check/testdata/facet/access.carbon @@ -367,61 +367,7 @@ fn F(U:! W, V:! Z(.Self) where .Z1 impls Y(U)) { V.(Z(V).Z1).(Y(U).Y1).(X.X1) as W; } -// --- find_access_value_in_second_nested_access.carbon -library "[[@TEST_NAME]]"; - -interface W {} -interface X { - let X1:! type; -} -interface Y(T:! type) { - let Y0:! type; - let Y1:! type; - let Y2:! type; -} -interface Z(U:! type, PeriodSelf:! type) { - let Z1:! Y(PeriodSelf) where .Y0 impls (X where .X1 = ()) - and .Y1 impls (X where .X1 = U) - and .Y2 impls (X where .X1 = ()) ; -} - -fn F(U:! W, V:! Z(U, .Self)) { - // This has to search for a value for `.Z1.Y1.X1` in V. To do so it needs to - // look for a rewrite of .X1. First it looks in `V.Z1.Y1`, then `V.Z1`, where - // it finds the rewrite of `.Y1.X1 = U`. - // - // Only U impls W so we use `as W` to test that the LHS is U. - V.(Z(U, V).Z1).(Y(V).Y1).(X.X1) as W; -} - -// --- find_access_value_in_third_nested_access.carbon -library "[[@TEST_NAME]]"; - -interface W {} -interface X { - let X1:! type; -} -interface Y { - let Y1:! type; -} -interface Z(T:! type) { - let Z0:! type; - let Z1:! type; - let Z2:! type; -} - -fn F(U:! W, V:! Z(.Self) where .Z0 impls (Y where .Y1 impls (X where .X1 = ())) - and .Z1 impls (Y where .Y1 impls (X where .X1 = U)) - and .Z2 impls (Y where .Y1 impls (X where .X1 = ()))) { - // This has to search for a value for `.Z1.Y1.X1` in V. To do so it needs to - // look for a rewrite of .X1. First it looks in `V.Z1.Y1`, then `V.Z1`, then - // `V` where it finds the rewrite of `.Z1.Y1.X1 = U`. - // - // Only U impls W so we use `as W` to test that the LHS is U. - V.(Z(V).Z1).(Y.Y1).(X.X1) as W; -} - -// --- fail_todo_find_access_value_in_second_nested_access_through_named_constraint.carbon +// --- fail_todo_find_access_value_in_second_nested_access.carbon library "[[@TEST_NAME]]"; interface W {} @@ -451,17 +397,17 @@ fn F(V:! Z(.Self)) { // // TODO: The identified facet type `NX` includes `X` and should provide a // same-type constraint `X.X1 == {}` which would allow this conversion. - // CHECK:STDERR: fail_todo_find_access_value_in_second_nested_access_through_named_constraint.carbon:[[@LINE+7]]:3: error: cannot convert expression of type `{}` to `V.(Z(V).Z1).(Y(V).Y1).(X.X1)` with `as` [ConversionFailure] + // CHECK:STDERR: fail_todo_find_access_value_in_second_nested_access.carbon:[[@LINE+7]]:3: error: cannot convert expression of type `{}` to `V.(Z(V).Z1).(Y(V).Y1).(X.X1)` with `as` [ConversionFailure] // CHECK:STDERR: {} as V.(Z(V).Z1).(Y(V).Y1).(X.X1); // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: fail_todo_find_access_value_in_second_nested_access_through_named_constraint.carbon:[[@LINE+4]]:3: note: type `{}` does not implement interface `Core.As(V.(Z(V).Z1).(Y(V).Y1).(X.X1))` [MissingImplInMemberAccessInContext] + // CHECK:STDERR: fail_todo_find_access_value_in_second_nested_access.carbon:[[@LINE+4]]:3: note: type `{}` does not implement interface `Core.As(V.(Z(V).Z1).(Y(V).Y1).(X.X1))` [MissingImplInMemberAccessInContext] // CHECK:STDERR: {} as V.(Z(V).Z1).(Y(V).Y1).(X.X1); // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: {} as V.(Z(V).Z1).(Y(V).Y1).(X.X1); } -// --- fail_todo_find_access_value_in_third_nested_access_through_named_constraint.carbon +// --- fail_todo_find_access_value_in_third_nested_access.carbon library "[[@TEST_NAME]]"; interface W {} @@ -481,21 +427,22 @@ constraint NX(V:! type) { extend require impls X where .X1 = V; } -fn F(V:! Z(.Self) where .Z0 impls (Y where .Y1 impls NX(())) - and .Z1 impls (Y where .Y1 impls NX({})) - and .Z2 impls (Y where .Y1 impls NX(()))) { +constraint NY(V:! type) { + extend require impls Y where .Y1 = NX(V); +} + +fn F(V:! Z(.Self) where .Z0 impls NY(()) + and .Z1 impls NY({}) + and .Z2 impls NY(())) { // This has to search for a value for `.Z1.Y1.X1` in V. To do so it needs to // look for a rewrite of .X1. First it looks in `V.Z1.Y1`, then `V.Z1`, then // `V` where it finds the rewrite of `.Z1.Y1.X1 = {}`. // // TODO: The identified facet type `NX` includes `X` and should provide a // same-type constraint `X.X1 == V` which would allow this conversion. - // CHECK:STDERR: fail_todo_find_access_value_in_third_nested_access_through_named_constraint.carbon:[[@LINE+7]]:3: error: cannot convert expression of type `{}` to `V.(Z(V).Z1).(Y.Y1).(X.X1)` with `as` [ConversionFailure] + // CHECK:STDERR: fail_todo_find_access_value_in_third_nested_access.carbon:[[@LINE+4]]:9: error: cannot convert type `V.(Z(V).Z1).(Y.Y1)` into type implementing `X` [ConversionFailureTypeToFacet] // CHECK:STDERR: {} as V.(Z(V).Z1).(Y.Y1).(X.X1); - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: fail_todo_find_access_value_in_third_nested_access_through_named_constraint.carbon:[[@LINE+4]]:3: note: type `{}` does not implement interface `Core.As(V.(Z(V).Z1).(Y.Y1).(X.X1))` [MissingImplInMemberAccessInContext] - // CHECK:STDERR: {} as V.(Z(V).Z1).(Y.Y1).(X.X1); - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: {} as V.(Z(V).Z1).(Y.Y1).(X.X1); } @@ -509,10 +456,14 @@ interface Y(T:! type) { } class C; -// TODO: We need to look in `T` for the rewrite in the access of `(C as -// Y(T)).Y1` but we currently only look in `C`. See the TODO in +constraint NY(PeriodSelf:! type) { + extend require impls Y(PeriodSelf) where .Y1 = {}; +} + +// TODO: We need to look in `T` for the rewrite in the access of +// `(C as Y(T)).Y1` but we currently only look in `C`. See the TODO in // `TryFindValueInRewriteConstraints()`. -fn F(T:! Z where C impls (Y(.Self) where .Y1 = {})) -> C.(Y(T).Y1) { +fn F(T:! Z where C impls NY(.Self)) -> C.(Y(T).Y1) { // CHECK:STDERR: fail_todo_find_access_value_in_facet_from_specific_interface.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `{}` to `C.(Y(T).Y1)` [ConversionFailure] // CHECK:STDERR: return {}; // CHECK:STDERR: ^~~~~~~~~~ diff --git a/toolchain/check/testdata/facet/early_impls.carbon b/toolchain/check/testdata/facet/early_impls.carbon index 06c20a9fd8a1..a3f2d5297f6f 100644 --- a/toolchain/check/testdata/facet/early_impls.carbon +++ b/toolchain/check/testdata/facet/early_impls.carbon @@ -244,7 +244,7 @@ constraint N(V:! type) { // CHECK:STDERR: fn F(_:! Z(.Self) where C impls N(.Z1) and .Z2 = (.Z1 as Y(.Self))) {} -// --- early_type_impls_nested_self_impls.carbon +// --- fail_todo_early_type_impls_nested_self_impls.carbon library "[[@TEST_NAME]]"; interface Z { @@ -258,10 +258,18 @@ interface X {} class C(T:! type); class D(T:! X); -// TODO: Does the `.Y1 impls X` contain an ambiguous `.Self`? See -// https://github.com/carbon-language/carbon-lang/issues/7138. +constraint NY { + require impls Y where .Y1 impls X; +} // A lookup of `C(V).(Y.Y1) as X` requires us to see that the `.Y1 impls X` -// constraint is visible through the `C(.Self) impls (Y...)` constraint and that +// constraint is visible through the `C(.Self) impls NY` constraint and that // `C(.Self)` is used as the implied `.Self` in `.Y1 impls X`. -fn F(unused V:! Z where C(.Self) impls (Y where .Y1 impls X) and .Z1 = D(C(.Self).(Y.Y1))) {} +// CHECK:STDERR: fail_todo_early_type_impls_nested_self_impls.carbon:[[@LINE+7]]:53: error: cannot convert type `C(.Self).(Y.Y1)` into type implementing `X` [ConversionFailureTypeToFacet] +// CHECK:STDERR: fn F(unused V:! Z where C(.Self) impls NY and .Z1 = D(C(.Self).(Y.Y1))) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: fail_todo_early_type_impls_nested_self_impls.carbon:[[@LINE-12]]:9: note: initializing generic parameter `T` declared here [InitializingGenericParam] +// CHECK:STDERR: class D(T:! X); +// CHECK:STDERR: ^~~~~ +// CHECK:STDERR: +fn F(unused V:! Z where C(.Self) impls NY and .Z1 = D(C(.Self).(Y.Y1))) {} diff --git a/toolchain/check/testdata/facet/early_rewrites.carbon b/toolchain/check/testdata/facet/early_rewrites.carbon index 5b154cb8ebeb..2e73a34fd488 100644 --- a/toolchain/check/testdata/facet/early_rewrites.carbon +++ b/toolchain/check/testdata/facet/early_rewrites.carbon @@ -384,7 +384,7 @@ fn G(T:! J where .J1 = D) { F(T); } -// --- early_rewrite_from_previous_impls_constraint.carbon +// --- fail_todo_early_rewrite_from_previous_impls_constraint.carbon library "[[@TEST_NAME]]"; interface Z { @@ -399,7 +399,18 @@ interface Tuple {} impl () as Tuple {} class C(U:! Tuple); -fn F(unused T:! Z where .Z1 impls (Y where .Y1 = ()) and .Z2 = C(.Z1.(Y.Y1))) {} +constraint NY(V:! type) { + extend require impls Y where .Y1 = V; +} + +// CHECK:STDERR: fail_todo_early_rewrite_from_previous_impls_constraint.carbon:[[@LINE+7]]:52: error: cannot convert type `.(Z.Z1).(Y.Y1)` into type implementing `Tuple` [ConversionFailureTypeToFacet] +// CHECK:STDERR: fn F(unused T:! Z where .Z1 impls NY(()) and .Z2 = C(.Z1.(Y.Y1))) {} +// CHECK:STDERR: ^~~~~~~~~~~~~ +// CHECK:STDERR: fail_todo_early_rewrite_from_previous_impls_constraint.carbon:[[@LINE-9]]:9: note: initializing generic parameter `U` declared here [InitializingGenericParam] +// CHECK:STDERR: class C(U:! Tuple); +// CHECK:STDERR: ^~~~~~~~~ +// CHECK:STDERR: +fn F(unused T:! Z where .Z1 impls NY(()) and .Z2 = C(.Z1.(Y.Y1))) {} // --- fail_early_rewrite_correct_interface_wrong_self_access_rewrite_in_period_self.carbon library "[[@TEST_NAME]]"; @@ -416,17 +427,21 @@ interface Tuple {} impl () as Tuple {} class C(U:! Tuple); +constraint NY(V:! type) { + extend require impls Y where .Y1 = V; +} + // This should fail: `T.(Y.Y1)` is rewritten to be `()` but `T.(Z.Z1).(Y.Y1)` // is used in the argument to `C`. // -// CHECK:STDERR: fail_early_rewrite_correct_interface_wrong_self_access_rewrite_in_period_self.carbon:[[@LINE+7]]:82: error: cannot convert type `.(Z.Z1).(Y.Y1)` into type implementing `Tuple` [ConversionFailureTypeToFacet] -// CHECK:STDERR: fn F(unused T:! Z where .Self impls (Y where .Y1 = ()) and .Z1 impls Y and .Z2 = C(.Z1.(Y.Y1))) {} -// CHECK:STDERR: ^~~~~~~~~~~~~ -// CHECK:STDERR: fail_early_rewrite_correct_interface_wrong_self_access_rewrite_in_period_self.carbon:[[@LINE-8]]:9: note: initializing generic parameter `U` declared here [InitializingGenericParam] +// CHECK:STDERR: fail_early_rewrite_correct_interface_wrong_self_access_rewrite_in_period_self.carbon:[[@LINE+7]]:70: error: cannot convert type `.(Z.Z1).(Y.Y1)` into type implementing `Tuple` [ConversionFailureTypeToFacet] +// CHECK:STDERR: fn F(unused T:! Z where .Self impls NY(()) and .Z1 impls Y and .Z2 = C(.Z1.(Y.Y1))) {} +// CHECK:STDERR: ^~~~~~~~~~~~~ +// CHECK:STDERR: fail_early_rewrite_correct_interface_wrong_self_access_rewrite_in_period_self.carbon:[[@LINE-12]]:9: note: initializing generic parameter `U` declared here [InitializingGenericParam] // CHECK:STDERR: class C(U:! Tuple); // CHECK:STDERR: ^~~~~~~~~ // CHECK:STDERR: -fn F(unused T:! Z where .Self impls (Y where .Y1 = ()) and .Z1 impls Y and .Z2 = C(.Z1.(Y.Y1))) {} +fn F(unused T:! Z where .Self impls NY(()) and .Z1 impls Y and .Z2 = C(.Z1.(Y.Y1))) {} // --- fail_early_rewrite_correct_interface_wrong_self_access_rewrite_in_associated_constant.carbon library "[[@TEST_NAME]]"; @@ -443,14 +458,18 @@ interface Tuple {} impl () as Tuple {} class C(U:! Tuple); +constraint NY(V:! type) { + extend require impls Y where .Y1 = V; +} + // This should fail: `T.(Z.Z1).(Y.Y1)` is rewritten to be `()` but `T.(Y.Y1)` is used // in the argument to `C`. // -// CHECK:STDERR: fail_early_rewrite_correct_interface_wrong_self_access_rewrite_in_associated_constant.carbon:[[@LINE+4]]:84: error: name `Self` not found [NameNotFound] -// CHECK:STDERR: fn G(unused T:! Z where .Z1 impls (Y where .Y1 = ()) and .Self impls Y and .Z2 = C(Self.(Y.Y1))) {} -// CHECK:STDERR: ^~~~ +// CHECK:STDERR: fail_early_rewrite_correct_interface_wrong_self_access_rewrite_in_associated_constant.carbon:[[@LINE+4]]:72: error: name `Self` not found [NameNotFound] +// CHECK:STDERR: fn G(unused T:! Z where .Z1 impls NY(()) and .Self impls Y and .Z2 = C(Self.(Y.Y1))) {} +// CHECK:STDERR: ^~~~ // CHECK:STDERR: -fn G(unused T:! Z where .Z1 impls (Y where .Y1 = ()) and .Self impls Y and .Z2 = C(Self.(Y.Y1))) {} +fn G(unused T:! Z where .Z1 impls NY(()) and .Self impls Y and .Z2 = C(Self.(Y.Y1))) {} // --- fail_nested_facet_type_in_rewrite_does_not_use_rewrite_from_outside.carbon library "[[@TEST_NAME]]"; @@ -460,17 +479,18 @@ interface Z { let Y:! type; } -// TODO: Does the `.X = .Y` contain an ambiguous `.Self` in `.Y`? See -// https://github.com/carbon-language/carbon-lang/issues/7138. +constraint NZ(PeriodY:! type) { + extend require impls Z where .X = PeriodY; +} -fn F(T:! Z where .Y = {} and .X = (Z where .X = .Y), U:! T.X) -> U.(Z.X) { +fn F(T:! Z where .Y = {} and .X = NZ(.Y), U:! T.X) -> U.(Z.X) { // This should fail: `U:! T.X` contains a rewrite `.X = .Y` in its type, but // the value of `U.(Z.Y)` is not known. Only `T.(Z.Y)` is rewritten to `{}`. // - // CHECK:STDERR: fail_nested_facet_type_in_rewrite_does_not_use_rewrite_from_outside.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `{}` to `U.(Z.Y)` [ConversionFailure] + // CHECK:STDERR: fail_nested_facet_type_in_rewrite_does_not_use_rewrite_from_outside.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `{}` to `U.(Z.X)` [ConversionFailure] // CHECK:STDERR: return {}; // CHECK:STDERR: ^~~~~~~~~~ - // CHECK:STDERR: fail_nested_facet_type_in_rewrite_does_not_use_rewrite_from_outside.carbon:[[@LINE+4]]:3: note: type `{}` does not implement interface `Core.ImplicitAs(U.(Z.Y))` [MissingImplInMemberAccessInContext] + // CHECK:STDERR: fail_nested_facet_type_in_rewrite_does_not_use_rewrite_from_outside.carbon:[[@LINE+4]]:3: note: type `{}` does not implement interface `Core.ImplicitAs(U.(Z.X))` [MissingImplInMemberAccessInContext] // CHECK:STDERR: return {}; // CHECK:STDERR: ^~~~~~~~~~ // CHECK:STDERR: diff --git a/toolchain/check/testdata/facet/nested_facet_types.carbon b/toolchain/check/testdata/facet/nested_facet_types.carbon index 454581329022..5e0c15229ab7 100644 --- a/toolchain/check/testdata/facet/nested_facet_types.carbon +++ b/toolchain/check/testdata/facet/nested_facet_types.carbon @@ -244,16 +244,20 @@ library "[[@TEST_NAME]]"; interface Y {} interface Z { - let T:! type; - let U:! type; + let Z1:! type; + let Z2:! type; } class C(T:! type) {} -fn F(unused FF:! ((Y where .Self impls (Z where .T = C(.U))) - where .Self impls (Z where .T = C(.U))) - where .Self impls (Z where .T = C(.U))) {} +constraint NZ { + extend require impls Z where .Z1 = C(.Z2); +} -// --- nested_impl_unique.carbon +fn F(unused FF:! ((Y where .Self impls NZ) + where .Self impls NZ) + where .Self impls NZ) {} + +// --- fail_todo_nested_impl_combine_rewrites_from_named_constraints.carbon library "[[@TEST_NAME]]"; interface Y { @@ -265,6 +269,64 @@ interface Z { } class C(T:! type) { adapt (); } -fn F(FF:! ((Y where .Y1 = ()) where .Self impls (Z where .Z1 = C(.Z2) and .Z2 = ()))) -> FF.(Z.Z1) { +constraint NZ1 { + // This uses the rewrite from NZ2. + extend require impls Z where .Z1 = C(.Z2); +} +constraint NZ2 { + extend require impls Z where .Z2 = (); +} + +fn F(FF:! ((Y where .Y1 = ()) where .Self impls NZ1) where .Self impls NZ2) -> FF.(Z.Z1) { + // CHECK:STDERR: fail_todo_nested_impl_combine_rewrites_from_named_constraints.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `C(())` to `FF.(Z.Z1)` [ConversionFailure] + // CHECK:STDERR: return () as C(()); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_todo_nested_impl_combine_rewrites_from_named_constraints.carbon:[[@LINE+4]]:3: note: type `C(())` does not implement interface `Core.ImplicitAs(FF.(Z.Z1))` [MissingImplInMemberAccessInContext] + // CHECK:STDERR: return () as C(()); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: return () as C(()); } + +// --- fail_where_nested_inside_where_impls.carbon +library "[[@TEST_NAME]]"; + +// CHECK:STDERR: fail_where_nested_inside_where_impls.carbon:[[@LINE+7]]:34: error: found `where` expression nested on the right-hand side of `where` [NestedWhereInsideWhere] +// CHECK:STDERR: fn F(_:! type where .Self impls (type where .Self impls type)) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: fail_where_nested_inside_where_impls.carbon:[[@LINE+4]]:10: note: on right-hand side of `where` here [NestedWhereInsideWhereOuterNote] +// CHECK:STDERR: fn F(_:! type where .Self impls (type where .Self impls type)) {} +// CHECK:STDERR: ^~~~~~~~~~ +// CHECK:STDERR: +fn F(_:! type where .Self impls (type where .Self impls type)) {} + +// --- fail_where_nested_inside_where_rewrite.carbon +library "[[@TEST_NAME]]"; + +interface Z { + let Z1:! type; +} + +// CHECK:STDERR: fail_where_nested_inside_where_rewrite.carbon:[[@LINE+7]]:25: error: found `where` expression nested on the right-hand side of `where` [NestedWhereInsideWhere] +// CHECK:STDERR: fn F(_:! Z where .Z1 = (type where .Self impls type)) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: fail_where_nested_inside_where_rewrite.carbon:[[@LINE+4]]:10: note: on right-hand side of `where` here [NestedWhereInsideWhereOuterNote] +// CHECK:STDERR: fn F(_:! Z where .Z1 = (type where .Self impls type)) {} +// CHECK:STDERR: ^~~~~~~ +// CHECK:STDERR: +fn F(_:! Z where .Z1 = (type where .Self impls type)) {} + +// --- fail_where_nested_inside_where_same_type.carbon +library "[[@TEST_NAME]]"; + +interface Z {} +class C; + +// CHECK:STDERR: fail_where_nested_inside_where_same_type.carbon:[[@LINE+7]]:24: error: found `where` expression nested on the right-hand side of `where` [NestedWhereInsideWhere] +// CHECK:STDERR: fn F(_:! Z where C == (type where .Self impls type)) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: fail_where_nested_inside_where_same_type.carbon:[[@LINE+4]]:10: note: on right-hand side of `where` here [NestedWhereInsideWhereOuterNote] +// CHECK:STDERR: fn F(_:! Z where C == (type where .Self impls type)) {} +// CHECK:STDERR: ^~~~~~~ +// CHECK:STDERR: +fn F(_:! Z where C == (type where .Self impls type)) {} diff --git a/toolchain/check/testdata/facet/nested_facet_types_from_eval.carbon b/toolchain/check/testdata/facet/nested_facet_types_from_eval.carbon new file mode 100644 index 000000000000..d121abf1e572 --- /dev/null +++ b/toolchain/check/testdata/facet/nested_facet_types_from_eval.carbon @@ -0,0 +1,62 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/full.carbon +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/facet/nested_facet_types_from_eval.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/facet/nested_facet_types_from_eval.carbon + +// --- todo_fail_where_nested_inside_where_through_alias.carbon +library "[[@TEST_NAME]]"; + +interface I {} +class C; + +alias A = I where .Self == C; + +// The use of `A` introduces a `where` expression inside the `where` written +// here, which is an error. +// +// TODO This should fail. +fn F(_:! type where .Self impls A) {} + +// --- todo_fail_where_nested_inside_where_through_fn_eval.carbon +library "[[@TEST_NAME]]"; + +interface I {} +class C; + +eval fn E() -> type { + return I where .Self == C; +} + +// The use of `E()` introduces a `where` expression inside the `where` +// written here, which is an error. +// +// TODO This should fail. +fn F(_:! type where .Self impls E()) {} + +// --- todo_fail_where_nested_inside_where_through_operator_eval.carbon +library "[[@TEST_NAME]]"; + +interface I {} +class C; + +class X1 { + impl type as Core.MulWith(X1) where .Result = type { + eval fn Op(unused self, _: X1) -> type { + return I where .Self == C; + } + } +} +alias X = {} as X1; + +// The use of `type * X` introduces a `where` expression inside the `where` +// written here, which is an error. +// +// TODO This should fail. +fn F(_:! type where .Self impls type * X) {} diff --git a/toolchain/check/testdata/facet/period_self.carbon b/toolchain/check/testdata/facet/period_self.carbon index 222cc4874ef1..972b5784b853 100644 --- a/toolchain/check/testdata/facet/period_self.carbon +++ b/toolchain/check/testdata/facet/period_self.carbon @@ -224,64 +224,6 @@ fn F(U:! Core.Destroy & I where .X = .Self) { let unused a: U = U.G(); } -// --- fail_todo_nested_period_self.carbon -library "[[@TEST_NAME]]"; - -interface I(T:! type) { - let A:! type; - let B:! type; - fn G() -> T; -} - -// Both `.Self` refer to `T`. The first because it's the interface for the -// binding. The second because it refers to the top level facet type which is -// constraining the binding. -fn F(T:! I(.Self) where .A = ((I(.Self) where .B = {}) where .A = {}) and .B = {}, U:! T.A) { - // T.G() has type T. - // CHECK:STDERR: fail_todo_nested_period_self.carbon:[[@LINE+7]]:21: error: cannot implicitly convert expression of type `.Self` to `T` [ConversionFailure] - // CHECK:STDERR: let unused t: T = T.G(); - // CHECK:STDERR: ^~~~~ - // CHECK:STDERR: fail_todo_nested_period_self.carbon:[[@LINE+4]]:21: note: type `.Self` does not implement interface `Core.ImplicitAs(T)` [MissingImplInMemberAccessInContext] - // CHECK:STDERR: let unused t: T = T.G(); - // CHECK:STDERR: ^~~~~ - // CHECK:STDERR: - let unused t: T = T.G(); - // U.G() has type T. - // CHECK:STDERR: fail_todo_nested_period_self.carbon:[[@LINE+7]]:21: error: cannot implicitly convert expression of type `.Self` to `T` [ConversionFailure] - // CHECK:STDERR: let unused u: T = U.G(); - // CHECK:STDERR: ^~~~~ - // CHECK:STDERR: fail_todo_nested_period_self.carbon:[[@LINE+4]]:21: note: type `.Self` does not implement interface `Core.ImplicitAs(T)` [MissingImplInMemberAccessInContext] - // CHECK:STDERR: let unused u: T = U.G(); - // CHECK:STDERR: ^~~~~ - // CHECK:STDERR: - let unused u: T = U.G(); - - // Shows both `I(.Self)` are `I(T)`. - // CHECK:STDERR: fail_todo_nested_period_self.carbon:[[@LINE+4]]:9: error: found cycle in facet type constraint for `.(I(T).A)` [FacetTypeConstraintCycle] - // CHECK:STDERR: T as (I(T) where .A = (I(T) where .A = {} and .B = {})); - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: - T as (I(T) where .A = (I(T) where .A = {} and .B = {})); - // CHECK:STDERR: fail_todo_nested_period_self.carbon:[[@LINE+4]]:3: error: cannot convert type `U` that implements `I(.Self) where .(I(.Self).B) = {} and .(I(.Self).A) = {}` into type implementing `I(T) where .(I(T).A) = {} and .(I(T).B) = {}` [ConversionFailureFacetToFacet] - // CHECK:STDERR: U as (I(T) where .A = {} and .B = {}); - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: - U as (I(T) where .A = {} and .B = {}); -} - -// --- todo_fail_nested_period_self_ambiguous.carbon -library "[[@TEST_NAME]]"; - -interface I(T:! type) { - let A:! type; -} - -// TODO: This should be an error: The third `.Self` becomes is not able to be -// bound to anything unambiguous here, as it could refer to `T` or to something -// later being constrained by `T.A`. -fn F(unused T:! I(.Self) where .A = (I(.Self) where .A = I(.Self))) {} - - // --- period_self_parameter_sees_lhs_of_where_expr.carbon library "[[@TEST_NAME]]"; @@ -321,118 +263,6 @@ fn F[U:! Core.Destroy where .Self impls I(.Self)](u: U) { u.(I(U).G)().(I(U).G)().(I(U).G)(); } -// --- unambiguous_period_self.carbon -library "[[@TEST_NAME]]"; - -interface Z(T:! type) {} -interface Y(T:! type) { - let Y1:! type; - let Y2:! type; -} -interface X(T:! type) {} - -class P; -class Q(T:! type); -class R(T:! type); - -fn A(unused T:! Z(.Self) where .Self impls (Y(.Self) where .Self impls X(.Self))) {} -// ^T as type ^T as Z(T) ^T as Z(T) ^T as Z(T) & Y(T) -// ^ T as Z(T) & Y(T) - -fn B(unused T:! Z(.Self) where .Self impls (Y(.Self) where Q(.Self) impls X(.Self))) {} -// ^T as type ^T as Z(T) ^T as Z(T) ^T as Z(T) & Y(T) -// ^ T as Z(T) & Y(T) - -fn C(unused T:! Z(.Self) where .Self impls (Y(.Self) where .Y1 = .Self)) {} -// ^T as type ^T as Z(T) ^T as Z(T) ^T as Z(T) & Y(T) -// ^ T as Z(T) & Y(T) - -// This introduces a different meaning of `.Self`, but we allow it here. -fn D(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where .Self impls X(P))) {} -// ^T as type ^T as Z(T) ^T as Z(T) ^R(T as Z(T)) as Y(T as Z(T)) - -// This introduces a different meaning of `.Self`, but we allow it here. -fn E(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where .Y1 = .Y2)) {} -// ^T as type ^T as Z(T) ^T as Z(T) ^R(T as Z(T)) as Y(T as Z(T)) -// ^R(T as Z(T)) as Y(T as Z(T)) - -// Member designators have an implicit `.Self` which is always allowed. It binds -// to the innermost facet value rather than being ambiguous. -fn F(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where .Self impls X(.Y1))) {} -// ^T as type ^T as Z(T) ^T as Z(T) ^R(T as Z(T)) as Y(T as Z(T)) -// ^Implicit: R(T as Z(T)) as Y(T as Z(T)) - -// --- fail_type_impls_ambiguous_period_self_argument.carbon -library "[[@TEST_NAME]]"; - -interface Z(T:! type) {} -interface Y(T:! type) {} -interface X(T:! type) {} -interface W {} - -class P; -class Q(T:! type); -class R(T:! type); - -// CHECK:STDERR: fail_type_impls_ambiguous_period_self_argument.carbon:[[@LINE+4]]:71: error: `.Self` is ambiguous after nested `where` in ` impls ...` clause. [AmbiguousPeriodSelf] -// CHECK:STDERR: fn A(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where P impls X(.Self))) {} -// CHECK:STDERR: ^~~~~~~~ -// CHECK:STDERR: -fn A(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where P impls X(.Self))) {} -// ^T as type ^T as Z(T) ^T as Z(T) ^ERROR: R(T as Z(T)) as Y(T as Z(T)) - -// --- fail_ambiguous_period_self_argument_impls.carbon -library "[[@TEST_NAME]]"; - -interface Z(T:! type) {} -interface Y(T:! type) {} -interface X {} - -class Q(T:! type); -class R(T:! type); - -// CHECK:STDERR: fail_ambiguous_period_self_argument_impls.carbon:[[@LINE+4]]:63: error: `.Self` is ambiguous after nested `where` in ` impls ...` clause. [AmbiguousPeriodSelf] -// CHECK:STDERR: fn B(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where Q(.Self) impls X)) {} -// CHECK:STDERR: ^~~~~~~~ -// CHECK:STDERR: -fn B(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where Q(.Self) impls X)) {} -// ^T as type ^T as Z(T) ^T as Z(T) ^ERROR: R(T as Z(T)) as Y(T as Z(T)) - -// --- fail_period_self_impls_ambiguous_period_self_argument.carbon -library "[[@TEST_NAME]]"; - -interface Z(T:! type) {} -interface Y(T:! type) {} -interface X(T:! type) {} - -class R(T:! type); - -// CHECK:STDERR: fail_period_self_impls_ambiguous_period_self_argument.carbon:[[@LINE+4]]:75: error: `.Self` is ambiguous after nested `where` in ` impls ...` clause. [AmbiguousPeriodSelf] -// CHECK:STDERR: fn C(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where .Self impls X(.Self))) {} -// CHECK:STDERR: ^~~~~~~~ -// CHECK:STDERR: -fn C(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where .Self impls X(.Self))) {} -// ^T as type ^T as Z(T) ^T as Z(T) ^R(T as Z(T)) as Y(T as Z(T)) -// ^ERROR: R(T as Z(T)) as Y(T as Z(T)) - -// --- fail_rewrite_rhs_ambiguous_period_self.carbon -library "[[@TEST_NAME]]"; - -interface Z(T:! type) {} -interface Y(T:! type) { - let Y1:! type; -} - -class R(T:! type); - -// CHECK:STDERR: fail_rewrite_rhs_ambiguous_period_self.carbon:[[@LINE+4]]:69: error: `.Self` is ambiguous after nested `where` in ` impls ...` clause. [AmbiguousPeriodSelf] -// CHECK:STDERR: fn D(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where .Y1 = .Self)) {} -// CHECK:STDERR: ^~~~~ -// CHECK:STDERR: -fn D(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where .Y1 = .Self)) {} -// ^T as type ^T as Z(T) ^T as Z(T) ^R(T as Z(T)) as Y(T as Z(T)) -// ^ERROR: R(T as Z(T)) as Y(T as Z(T)) - // --- impl_as_rewrite_with_period_self.carbon library "[[@TEST_NAME]]"; diff --git a/toolchain/check/testdata/facet/validate_impl_constraints.carbon b/toolchain/check/testdata/facet/validate_impl_constraints.carbon index 5ec3d000ca05..875cd87598d1 100644 --- a/toolchain/check/testdata/facet/validate_impl_constraints.carbon +++ b/toolchain/check/testdata/facet/validate_impl_constraints.carbon @@ -10,14 +10,25 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/facet/validate_impl_constraints.carbon -// --- self_impls_modifies_assoc_constant.carbon +// --- fail_todo_self_impls_modifies_assoc_constant.carbon library "[[@TEST_NAME]]"; interface I { let X:! type; } fn F(unused T:! I where .X = ()) {} -fn G(T:! I where .Self impls (I where .X = ())) { +constraint N { + extend require impls I where .X = (); +} + +fn G(T:! I where .Self impls N) { + // CHECK:STDERR: fail_todo_self_impls_modifies_assoc_constant.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `I where .Self impls N` into type implementing `I where .(I.X) = ()` [ConversionFailureFacetToFacet] + // CHECK:STDERR: F(T); + // CHECK:STDERR: ^~~~ + // CHECK:STDERR: fail_todo_self_impls_modifies_assoc_constant.carbon:[[@LINE-10]]:13: note: initializing generic parameter `T` declared here [InitializingGenericParam] + // CHECK:STDERR: fn F(unused T:! I where .X = ()) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: F(T); } @@ -28,18 +39,22 @@ interface I { let X:! type; } fn F(unused T:! I where .X = ()) {} -fn G(T:! I where .Self impls (I where .X = {})) { - // CHECK:STDERR: fail_self_impls_modifies_assoc_constant_type_differs.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `I where .(I.X) = {}` into type implementing `I where .(I.X) = ()` [ConversionFailureFacetToFacet] +constraint N { + extend require impls I where .X = {}; +} + +fn G(T:! I where .Self impls N) { + // CHECK:STDERR: fail_self_impls_modifies_assoc_constant_type_differs.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `I where .Self impls N` into type implementing `I where .(I.X) = ()` [ConversionFailureFacetToFacet] // CHECK:STDERR: F(T); // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_self_impls_modifies_assoc_constant_type_differs.carbon:[[@LINE-6]]:13: note: initializing generic parameter `T` declared here [InitializingGenericParam] + // CHECK:STDERR: fail_self_impls_modifies_assoc_constant_type_differs.carbon:[[@LINE-10]]:13: note: initializing generic parameter `T` declared here [InitializingGenericParam] // CHECK:STDERR: fn F(unused T:! I where .X = ()) {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: F(T); } -// --- fail_where_impls_tests_associated_constant_of_generic_type_non_final_impl.carbon +// --- todo_fail_where_impls_tests_associated_constant_of_generic_type_non_final_impl.carbon library "[[@TEST_NAME]]"; class C(U:! type) {} @@ -49,23 +64,22 @@ interface L {} interface M { let M0:! type; } impl forall [U:! L] C(U) as M where .M0 = {} {} +constraint M0IsStruct { + extend require impls M where .M0 = {}; +} + // U requires that C(.Self) impls M. // - C(.Self) impls M can be rewritten as C(U) impls M. // - C(U) impls M if U impls L => Requires U impls L. -fn F(unused U:! type where C(.Self) impls (M where .M0 = {})) {} +fn F(unused U:! type where C(.Self) impls M0IsStruct) {} fn G(T:! L) { // We have no final impl for `C(T) as M`, so we don't know the value of // `(C(T) as M).M0` concretely, so we don't know that it is `{}` and we can't // convert assuming it is. // - // CHECK:STDERR: fail_where_impls_tests_associated_constant_of_generic_type_non_final_impl.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `L` into type implementing `type where C(.Self) impls M and C(.Self).(M.M0) = {}` [ConversionFailureFacetToFacet] - // CHECK:STDERR: F(T); - // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_where_impls_tests_associated_constant_of_generic_type_non_final_impl.carbon:[[@LINE-10]]:13: note: initializing generic parameter `U` declared here [InitializingGenericParam] - // CHECK:STDERR: fn F(unused U:! type where C(.Self) impls (M where .M0 = {})) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: + // TODO: This should fail. The rewrite constraint from `M0IsStruct` is not + // being checked. F(T); } @@ -79,16 +93,20 @@ interface L {} interface M { let M0:! type; } final impl forall [U:! L] C(U) as M where .M0 = {} {} +constraint M0IsStruct { + extend require impls M where .M0 = {}; +} + // U requires that C(.Self) impls M. // - C(.Self) impls M can be rewritten as C(U) impls M. // - C(U) impls M if U impls L => Requires U impls L. -fn F(unused U:! type where C(.Self) impls (M where .M0 = {})) {} +fn F(unused U:! type where C(.Self) impls M0IsStruct) {} fn G(T:! L) { F(T); } -// --- fail_where_impls_tests_associated_constant_of_generic_type_type_differs.carbon +// --- todo_fail_where_impls_tests_associated_constant_of_generic_type_type_differs.carbon library "[[@TEST_NAME]]"; class C(U:! type) {} @@ -98,23 +116,23 @@ interface L {} interface M { let M0:! type; } final impl forall [U:! L] C(U) as M where .M0 = () {} +constraint M0IsStruct { + extend require impls M where .M0 = {}; +} + // U requires that C(.Self) impls M. // - C(.Self) impls M can be rewritten as C(U) impls M. // - C(U) impls M if U impls L => Requires U impls L. -fn F(unused U:! type where C(.Self) impls (M where .M0 = {})) {} +fn F(unused U:! type where C(.Self) impls M0IsStruct) {} fn G(T:! L) { - // CHECK:STDERR: fail_where_impls_tests_associated_constant_of_generic_type_type_differs.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `L` into type implementing `type where C(.Self) impls M and C(.Self).(M.M0) = {}` [ConversionFailureFacetToFacet] - // CHECK:STDERR: F(T); - // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_where_impls_tests_associated_constant_of_generic_type_type_differs.carbon:[[@LINE-6]]:13: note: initializing generic parameter `U` declared here [InitializingGenericParam] - // CHECK:STDERR: fn F(unused U:! type where C(.Self) impls (M where .M0 = {})) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: + // F requires .M0 = {}, but the final impl provides .M0 = (). + // + // TODO: This should fail. F(T); } -// --- fail_where_impls_tests_associated_constant_of_generic_interface_non_final_impl.carbon +// --- todo_fail_where_impls_tests_associated_constant_of_generic_interface_non_final_impl.carbon library "[[@TEST_NAME]]"; class C {} @@ -124,23 +142,21 @@ interface L {} interface M(U:! type) { let M0:! type; } impl forall [U:! L] C as M(U) where .M0 = {} {} +constraint M0IsStruct(PeriodSelf:! type) { + extend require impls M(PeriodSelf) where .M0 = {}; +} + // U requires that C impls M(.Self). // - C impls M(.Self) can be rewritten as C impls M(U). // - C impls M(U) if U impls L => Requires U impls L. -fn F(unused U:! type where C impls (M(.Self) where .M0 = {})) {} +fn F(unused U:! type where C impls M0IsStruct(.Self)) {} fn G(T:! L) { // We have no final impl for `C as M(T)`, so we don't know the value of // `(C as M(T)).M0` concretely, so we don't know that it is `{}` and we can't // convert assuming it is. // - // CHECK:STDERR: fail_where_impls_tests_associated_constant_of_generic_interface_non_final_impl.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `L` into type implementing `type where C impls M(.Self) and C.(M(.Self).M0) = {}` [ConversionFailureFacetToFacet] - // CHECK:STDERR: F(T); - // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_where_impls_tests_associated_constant_of_generic_interface_non_final_impl.carbon:[[@LINE-10]]:13: note: initializing generic parameter `U` declared here [InitializingGenericParam] - // CHECK:STDERR: fn F(unused U:! type where C impls (M(.Self) where .M0 = {})) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: + // TODO: This should fail. F(T); } @@ -154,16 +170,20 @@ interface L {} interface M(U:! type) { let M0:! type; } final impl forall [U:! L] C as M(U) where .M0 = {} {} +constraint M0IsStruct(PeriodSelf:! type) { + extend require impls M(PeriodSelf) where .M0 = {}; +} + // U requires that C impls M(.Self). // - C impls M(.Self) can be rewritten as C impls M(U). // - C impls M(U) if U impls L => Requires U impls L. -fn F(unused U:! type where C impls (M(.Self) where .M0 = {})) {} +fn F(unused U:! type where C impls M0IsStruct(.Self)) {} fn G(T:! L) { F(T); } -// --- fail_where_impls_tests_associated_constant_of_generic_interface_type_differs.carbon +// --- todo_fail_where_impls_tests_associated_constant_of_generic_interface_type_differs.carbon library "[[@TEST_NAME]]"; class C {} @@ -173,19 +193,19 @@ interface L {} interface M(U:! type) { let M0:! type; } final impl forall [U:! L] C as M(U) where .M0 = () {} +constraint M0IsStruct(PeriodSelf:! type) { + extend require impls M(PeriodSelf) where .M0 = {}; +} + // U requires that C impls M(.Self). // - C impls M(.Self) can be rewritten as C impls M(U). // - C impls M(U) if U impls L => Requires U impls L. -fn F(unused U:! type where C impls (M(.Self) where .M0 = {})) {} +fn F(unused U:! type where C impls M0IsStruct(.Self)) {} fn G(T:! L) { - // CHECK:STDERR: fail_where_impls_tests_associated_constant_of_generic_interface_type_differs.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `L` into type implementing `type where C impls M(.Self) and C.(M(.Self).M0) = {}` [ConversionFailureFacetToFacet] - // CHECK:STDERR: F(T); - // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_where_impls_tests_associated_constant_of_generic_interface_type_differs.carbon:[[@LINE-6]]:13: note: initializing generic parameter `U` declared here [InitializingGenericParam] - // CHECK:STDERR: fn F(unused U:! type where C impls (M(.Self) where .M0 = {})) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: + // F requires that .M0 = {} but the final impl provides that .M0 = (). + // + // TODO: This should fail. F(T); } @@ -276,39 +296,6 @@ fn G() { F(C); } -// --- fail_todo_where_period_self_rhs_impls_nested_period_self.carbon -library "[[@TEST_NAME]]"; - -interface Z {} -interface Y {} -interface X(T:! Z & Y) {} - -constraint N { - require impls Y; -} - -// TODO: The inner nested facet type (`N where...`) does not know about -// constraints on the outer facet type (`Z where...`). But it should produce an -// implied constraint that `.Self impls Z & Y` that is checked once the full -// facet type is known. -// -// CHECK:STDERR: fail_todo_where_period_self_rhs_impls_nested_period_self.carbon:[[@LINE+7]]:51: error: cannot convert type `.Self` that implements `N` into type implementing `Z & Y` [ConversionFailureFacetToFacet] -// CHECK:STDERR: fn F(_:! Z where .Self impls (N where .Self impls X(.Self))) {} -// CHECK:STDERR: ^~~~~~~~ -// CHECK:STDERR: fail_todo_where_period_self_rhs_impls_nested_period_self.carbon:[[@LINE-14]]:13: note: initializing generic parameter `T` declared here [InitializingGenericParam] -// CHECK:STDERR: interface X(T:! Z & Y) {} -// CHECK:STDERR: ^~~~~~~~~ -// CHECK:STDERR: -fn F(_:! Z where .Self impls (N where .Self impls X(.Self))) {} - -fn G() { - class C; - impl C as Z {} - impl C as Y {} - impl C as X(C) {} - F(C); -} - // --- associated_const_impls_interface_with_period_self.carbon library "[[@TEST_NAME]]"; diff --git a/toolchain/check/testdata/facet/validate_rewrite_constraints.carbon b/toolchain/check/testdata/facet/validate_rewrite_constraints.carbon index 973fd7997343..b10f290baf92 100644 --- a/toolchain/check/testdata/facet/validate_rewrite_constraints.carbon +++ b/toolchain/check/testdata/facet/validate_rewrite_constraints.carbon @@ -556,9 +556,9 @@ library "[[@TEST_NAME]]"; interface I { let X:! type; } interface K(Y:! type) { } -fn F(unused T:! I where .X = {.k: K(I where .X = ())}) {} +fn F(unused T:! I where .X = {.k: K(I)}) {} -fn G(T:! I where .X = {.k: K(I where .X = ())}) { +fn G(T:! I where .X = {.k: K(I)}) { F(T); } @@ -717,25 +717,6 @@ fn H(T:! I where .X1 = .Self and .X2 = .X1.X3 and .X3 = ()) { G(T); } -// --- associated_constant_is_facet_type_of_same_interface.carbon -library "[[@TEST_NAME]]"; - -interface I { - let A:! type; - let X:! type; -} - -class C; - -// This looks for a bug where `.Self.A` resolves to `C` from `.T.A` in the -// incoming facet value, which is incorrect. It should be `.T.X.A` which -// resolves to `{}`. -fn F(unused U:! I where .X = (I where .A = {})) {} - -fn G(T:! I where .X = (I where .A = {}) and .A = C) { - F(T); -} - // --- rewrite_requires_subst_in_rhs.carbon library "[[@TEST_NAME]]"; @@ -752,58 +733,6 @@ fn G(T:! I where .X = C({}) and .Y = {}) { F(T); } -// --- fail_todo_rewrite_requires_subst_in_nested_facet_type.carbon -library "[[@TEST_NAME]]"; - -interface I(T:! type) { - let X:! type; - let Y:! type; -} - -class C; - -fn F(unused T:! I(C) where .X = (I(.Y) where .Y = ())) {} - -fn G(T:! I(C) where .X = (I({}) where .Y = ()) and .Y = {}) { - // TODO: The T in G should match the T in F, once the .Self reference to the - // top level facet value in `I(.Y)` is correctly substituted by tracking that - // it is a .Self reference to the top level Self. - // CHECK:STDERR: fail_todo_rewrite_requires_subst_in_nested_facet_type.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `I(C) where .(I(C).X) = I({}) where .(I({}).Y) = () and .(I(C).Y) = {}` into type implementing `I(C) where .(I(C).X) = I(.(I(C).Y)) where .(I(.(I(C).Y)).Y) = ()` [ConversionFailureFacetToFacet] - // CHECK:STDERR: F(T); - // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_todo_rewrite_requires_subst_in_nested_facet_type.carbon:[[@LINE-9]]:13: note: initializing generic parameter `T` declared here [InitializingGenericParam] - // CHECK:STDERR: fn F(unused T:! I(C) where .X = (I(.Y) where .Y = ())) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: - F(T); -} - -fn G2(T:! I(C) where .X = (I(.Y) where .Y = ()) and .Y = {}) { - F(T); -} - -// --- fail_rewrite_requires_subst_in_nested_facet_type_types_differ.carbon -library "[[@TEST_NAME]]"; - -interface I(T:! type) { - let X:! type; - let Y:! type; -} - -fn F(unused T:! I({}) where .X = (I(.Y) where .X = ())) {} - -// I(.Y) is I({}) which doesn't match I(()). -fn G(T:! I({}) where .X = (I(()) where .X = ()) and .Y = {}) { - // CHECK:STDERR: fail_rewrite_requires_subst_in_nested_facet_type_types_differ.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `I({}) where .(I({}).X) = I(()) where .(I(()).X) = () and .(I({}).Y) = {}` into type implementing `I({}) where .(I({}).X) = I(.(I({}).Y)) where .(I(.(I({}).Y)).X) = ()` [ConversionFailureFacetToFacet] - // CHECK:STDERR: F(T); - // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_rewrite_requires_subst_in_nested_facet_type_types_differ.carbon:[[@LINE-7]]:13: note: initializing generic parameter `T` declared here [InitializingGenericParam] - // CHECK:STDERR: fn F(unused T:! I({}) where .X = (I(.Y) where .X = ())) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: - F(T); -} - // --- facet_type_in_assoc_constant.carbon library "[[@TEST_NAME]]"; @@ -811,10 +740,11 @@ interface I { let X:! type; let Y:! type; } +interface J(T:! type) {} -fn F(unused T:! I where .X = (I where .X = () and .Y = ())) {} +fn F(unused T:! I where .X = J(())) {} -fn G(T:! I where .X = (I where .X = .Y and .Y = ())) { +fn G(T:! I where .X = J(()) and .Y = ()) { F(T); } @@ -826,189 +756,21 @@ interface I { let Y:! type; let Z:! type; } +interface J(T:! type) {} -fn F(unused T:! I where .X = (I where .X = .Y)) {} +fn F(unused T:! I where .X = J(())) {} -fn G(T:! I where .X = (I where .X = () and .Y = () and .Z = {})) { - // CHECK:STDERR: fail_facet_type_in_assoc_constant_differs.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `I where .(I.X) = I where .(I.X) = () and .(I.Y) = () and .(I.Z) = {}` into type implementing `I where .(I.X) = I where .(I.X) = .(I.Y)` [ConversionFailureFacetToFacet] +fn G(T:! I where .X = J({}) and .Y = ()) { + // CHECK:STDERR: fail_facet_type_in_assoc_constant_differs.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `I where .(I.X) = J({}) and .(I.Y) = ()` into type implementing `I where .(I.X) = J(())` [ConversionFailureFacetToFacet] // CHECK:STDERR: F(T); // CHECK:STDERR: ^~~~ // CHECK:STDERR: fail_facet_type_in_assoc_constant_differs.carbon:[[@LINE-6]]:13: note: initializing generic parameter `T` declared here [InitializingGenericParam] - // CHECK:STDERR: fn F(unused T:! I where .X = (I where .X = .Y)) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fn F(unused T:! I where .X = J(())) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: F(T); } -// --- nested_facet_type_in_assoc_constant.carbon -library "[[@TEST_NAME]]"; - -interface I { - let X:! type; - let Y:! type; - let Z:! type; -} - -fn F(unused T:! I where .X = (I where .Y = (I where .X = () and .Y = ()))) {} - -fn G(T:! I where .X = (I where .Y = (I where .X = .Y and .Y = ()))) { - F(T); -} - -// --- fail_nested_facet_type_assigns_same_assoc_constant.carbon -library "[[@TEST_NAME]]"; - -interface I { - let X:! type; - let Y:! type; -} - -fn F(unused T:! I where .Y = ()) {} - -// The `.Y = ()` is on a different `.Self` than `T` (an unattached self), so -// should not satisfy `F`. -fn G(T:! I where .X = (I where .Y = ())) { - // CHECK:STDERR: fail_nested_facet_type_assigns_same_assoc_constant.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `I where .(I.X) = I where .(I.Y) = ()` into type implementing `I where .(I.Y) = ()` [ConversionFailureFacetToFacet] - // CHECK:STDERR: F(T); - // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_nested_facet_type_assigns_same_assoc_constant.carbon:[[@LINE-8]]:13: note: initializing generic parameter `T` declared here [InitializingGenericParam] - // CHECK:STDERR: fn F(unused T:! I where .Y = ()) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: - F(T); -} - -// --- fail_nested_facet_type_in_assoc_constant_differs.carbon -library "[[@TEST_NAME]]"; - -interface I { - let X:! type; - let Y:! type; - let Z:! type; -} - -fn F(unused T:! I where .X = (I where .Y = (I where .X = .Y))) {} - -// `.X = .Y` does not match `.X = () and .Y = ()` as they are different resolved -// facet types. -fn G(T:! I where .X = (I where .Y = (I where .X = () and .Y = ()))) { - // CHECK:STDERR: fail_nested_facet_type_in_assoc_constant_differs.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `I where .(I.X) = I where .(I.Y) = I where .(I.X) = () and .(I.Y) = ()` into type implementing `I where .(I.X) = I where .(I.Y) = I where .(I.X) = .(I.Y)` [ConversionFailureFacetToFacet] - // CHECK:STDERR: F(T); - // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_nested_facet_type_in_assoc_constant_differs.carbon:[[@LINE-8]]:13: note: initializing generic parameter `T` declared here [InitializingGenericParam] - // CHECK:STDERR: fn F(unused T:! I where .X = (I where .Y = (I where .X = .Y))) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: - F(T); -} - -// The extra .Z rewrite makes a different resolved facet type which does not -// match. -fn G2(T:! I where .X = (I where .Y = (I where .X = .Y and .Z = {}))) { - // CHECK:STDERR: fail_nested_facet_type_in_assoc_constant_differs.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `I where .(I.X) = I where .(I.Y) = I where .(I.X) = .(I.Y) and .(I.Z) = {}` into type implementing `I where .(I.X) = I where .(I.Y) = I where .(I.X) = .(I.Y)` [ConversionFailureFacetToFacet] - // CHECK:STDERR: F(T); - // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_nested_facet_type_in_assoc_constant_differs.carbon:[[@LINE-21]]:13: note: initializing generic parameter `T` declared here [InitializingGenericParam] - // CHECK:STDERR: fn F(unused T:! I where .X = (I where .Y = (I where .X = .Y))) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: - F(T); -} - -// --- fail_nested_facet_type_from_constant.carbon -library "[[@TEST_NAME]]"; - -interface I { - let X:! type; - let Y:! type; -} - -fn F(unused T:! I where .X = (I where .Y = (I where .X = .Y, ))) {} - -// References to named constants in a facet type don't work at all. If they did, -// then when the `Constant` facet type is put into the RHS of a rewrite -// constraint, its references to `.Self` must be modified to not refer to the -// top level `.Self` which is `T`. If done correctly, they will match the -// `.Self` references in the same position in the parameter of `F`. If not, the -// `.X` within becomes self-referential and makes a cycle. - -fn G1() { - // CHECK:STDERR: fail_nested_facet_type_from_constant.carbon:[[@LINE+4]]:7: error: semantics TODO: `local `let :!` bindings are currently unsupported` [SemanticsTodo] - // CHECK:STDERR: let Constant:! type = I where .X = .Y; - // CHECK:STDERR: ^~~~~~~~~~~~~~~ - // CHECK:STDERR: - let Constant:! type = I where .X = .Y; - - fn G(T:! I where .X = (I where .Y = (Constant, ))) { - F(T); - } -} - -fn G2() { - let Constant:! type = (I where .X = .Y, ); - - fn G(T:! I where .X = (I where .Y = Constant)) { - F(T); - } -} - -fn G3() { - let Constant:! type = I where .Y = (I where .X = .Y, ); - - fn G(T:! I where .X = Constant) { - F(T); - } -} - -fn G4() { - let Constant2:! type = (I where .X = .Y, ); - let Constant:! type = Constant2; - - fn G(T:! I where .X = (I where .Y = Constant)) { - F(T); - } -} - -fn G5() { - let Constant2:! type = I where .X = .Y; - let Constant:! type = (Constant2, ); - - fn G(T:! I where .X = (I where .Y = Constant)) { - F(T); - } -} - -fn G6() { - let Constant2:! type = (I where .X = .Y, ); - let Constant:! type = I where .Y = Constant2; - - fn G(T:! I where .X = Constant) { - F(T); - } -} - -// --- fail_nested_facet_type_from_constant_differs.carbon -library "[[@TEST_NAME]]"; - -interface I { - let X:! type; - let Y:! type; -} - -fn F(unused T:! I where .X = (I where .Y = (I where .X = .Y, ))) {} - -fn G1() { - // CHECK:STDERR: fail_nested_facet_type_from_constant_differs.carbon:[[@LINE+4]]:7: error: semantics TODO: `local `let :!` bindings are currently unsupported` [SemanticsTodo] - // CHECK:STDERR: let Constant:! type = I where .X = () and .Y = (); - // CHECK:STDERR: ^~~~~~~~~~~~~~~ - // CHECK:STDERR: - let Constant:! type = I where .X = () and .Y = (); - - fn G(T:! I where .X = (I where .Y = (Constant, ))) { - F(T); - } -} - // --- rewrite_rhs_satisfies_lhs_requirement.carbon library "[[@TEST_NAME]]"; @@ -1335,7 +1097,7 @@ fn G(T:! I where .I1 = .I2) { F(T); } -// --- nested_facet_type_used_as_root_facet_type.carbon +// --- nested_facet_type_used_as_root_facet_type_in_callee.carbon library "[[@TEST_NAME]]"; interface I { @@ -1343,9 +1105,118 @@ interface I { let Y:! type; } -fn F(T:! I where .X = (I where .Y = {}), unused U:! T.X) {} +constraint NI(V:! type) { + extend require impls I where .Y = V; +} -fn G(T:! I where .X = (I where .Y = {}), U:! I where .Y = {}) { +fn F(T:! I where .X = NI({}), unused U:! T.X) {} + +fn G(T:! I where .X = NI({}), U:! I where .Y = {}) { + F(T, U); +} + +// --- fail_todo_nested_facet_type_used_as_root_facet_type_in_caller.carbon +library "[[@TEST_NAME]]"; + +interface I { + let X:! type; + let Y:! type; +} + +constraint NI(V:! type) { + extend require impls I where .Y = V; +} + +fn F(unused T:! I where .X = NI({}), unused U:! I where .Y = {}) {} + +fn G(T:! I where .X = NI({}), U:! T.X) { + // TODO: This should pass, the rewrite in the constraint `NI` should be visible. + // CHECK:STDERR: fail_todo_nested_facet_type_used_as_root_facet_type_in_caller.carbon:[[@LINE+7]]:3: error: cannot convert type `U` that implements `NI({})` into type implementing `I where .(I.Y) = {}` [ConversionFailureFacetToFacet] + // CHECK:STDERR: F(T, U); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_nested_facet_type_used_as_root_facet_type_in_caller.carbon:[[@LINE-7]]:45: note: initializing generic parameter `U` declared here [InitializingGenericParam] + // CHECK:STDERR: fn F(unused T:! I where .X = NI({}), unused U:! I where .Y = {}) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + F(T, U); +} + +// --- fail_nested_facet_type_used_as_root_facet_type_differs_in_interface.carbon +library "[[@TEST_NAME]]"; + +interface I { + let X:! type; + let Y:! type; +} +interface J { + let X:! type; + let Y:! type; +} + +constraint NI(V:! type) { + extend require impls I where .Y = V; +} + +fn F(T:! I where .X = NI({}), unused U:! T.X) {} + +fn G(T:! I where .X = NI({}), U:! J where .Y = ()) { + // CHECK:STDERR: fail_nested_facet_type_used_as_root_facet_type_differs_in_interface.carbon:[[@LINE+7]]:3: error: cannot convert type `U` that implements `J where .(J.Y) = ()` into type implementing `NI({})` [ConversionFailureFacetToFacet] + // CHECK:STDERR: F(T, U); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_nested_facet_type_used_as_root_facet_type_differs_in_interface.carbon:[[@LINE-6]]:38: note: initializing generic parameter `U` declared here [InitializingGenericParam] + // CHECK:STDERR: fn F(T:! I where .X = NI({}), unused U:! T.X) {} + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + F(T, U); +} + +// --- todo_fail_nested_facet_type_used_as_root_facet_type_differs_in_rewrite_callee_access.carbon +library "[[@TEST_NAME]]"; + +interface I { + let X:! type; + let Y:! type; +} + +constraint NI(V:! type) { + extend require impls I where .Y = V; +} + +fn F(T:! I where .X = NI({}), unused U:! T.X) {} + +fn G(T:! I where .X = NI({}), U:! I where .Y = ()) { + // The caller's `U` has type `I where .Y = ()` but the callee wants something + // of type `I where .Y = {}`. + // + // TODO: This should fail. + F(T, U); +} + +// --- fail_nested_facet_type_used_as_root_facet_type_differs_in_rewrite_caller_access.carbon +library "[[@TEST_NAME]]"; + +interface I { + let X:! type; + let Y:! type; +} + +constraint NI(V:! type) { + extend require impls I where .Y = V; +} + +fn F(unused T:! I where .X = NI({}), unused U:! I where .Y = ()) {} + +fn G(T:! I where .X = NI({}), U:! T.X) { + // The caller's `U` has type `I where .Y = {}` but the callee wants something + // of type `I where .Y = ()`. + // + // CHECK:STDERR: fail_nested_facet_type_used_as_root_facet_type_differs_in_rewrite_caller_access.carbon:[[@LINE+7]]:3: error: cannot convert type `U` that implements `NI({})` into type implementing `I where .(I.Y) = ()` [ConversionFailureFacetToFacet] + // CHECK:STDERR: F(T, U); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_nested_facet_type_used_as_root_facet_type_differs_in_rewrite_caller_access.carbon:[[@LINE-9]]:45: note: initializing generic parameter `U` declared here [InitializingGenericParam] + // CHECK:STDERR: fn F(unused T:! I where .X = NI({}), unused U:! I where .Y = ()) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: F(T, U); } @@ -1417,81 +1288,141 @@ fn G(T:! I where .I1 = {}) { // --- resolve_nested_impl_witness_access.carbon library "[[@TEST_NAME]]"; -interface Y { - let Y1:! type; -} interface Z { - let Z1:! Y; + let Z1:! type; let Z2:! type; } fn G(_:! Z where .Z2 = ()) {} -// Split the assignment of .Y1 and the use of it into separate facet types so -// that the early rewrite application doesn't get to see the value of .Y1 where +// Split the assignment of .Z1 and the use of it into separate facet types so +// that the early rewrite application doesn't get to see the value of .Z1 where // it's used. Then rewrite constraint resolution has to do the replacement of -// .Z1.Y1 so that we know .Z2 = () as required by G. -fn F(T:! (Z where .Z1 impls (Y where .Y1 = ())) & (Z where .Z2 = .Z1.Y1)) { +// .Z1 so that we know .Z2 = () as required by G. +fn F(T:! (Z where .Z1 = ()) & (Z where .Z2 = .Z1)) { G(T); } -// --- rewrite_in_impls_provided_by_facet_type.carbon +// --- rewrite_provided_by_facet_type.carbon library "[[@TEST_NAME]]"; interface Z { let Z1:! type; + let Z2:! type; } -fn F(_:! type where .Self impls (Z where .Z1 = {})) {} +fn F(_:! Z where .Z1 = {}) {} -fn G(T:! Z where .Z1 = {}) { +fn G(T:! Z where .Z1 = {} and .Z2 = {}) { + //@dump-sem-ir-begin + // We should see a conversion happen so we know the rewrite constraint is + // being validated. F(T); + //@dump-sem-ir-end } -// --- fail_todo_rewrite_in_impls_provided_by_extend_named_constraint.carbon +// --- fail_todo_rewrite_provided_by_named_constraint.carbon library "[[@TEST_NAME]]"; interface Z { let Z1:! type; } -fn F(_:! type where .Self impls (Z where .Z1 = {})) {} +fn F(_:! Z where .Z1 = {}) {} constraint N { + // The extend means that the rewrite constraint is propagated out of `N`, so + // it can satisfy the requirement in `F` that `.Z1` is rewritten to `{}`. extend require impls Z where .Z1 = {}; } fn G(T:! N) { - // CHECK:STDERR: fail_todo_rewrite_in_impls_provided_by_extend_named_constraint.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `N` into type implementing `type where .Self impls Z and .(Z.Z1) = {}` [ConversionFailureFacetToFacet] + // TODO: This should pass. + // CHECK:STDERR: fail_todo_rewrite_provided_by_named_constraint.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `N` into type implementing `Z where .(Z.Z1) = {}` [ConversionFailureFacetToFacet] // CHECK:STDERR: F(T); // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_todo_rewrite_in_impls_provided_by_extend_named_constraint.carbon:[[@LINE-10]]:6: note: initializing generic parameter `_` declared here [InitializingGenericParam] - // CHECK:STDERR: fn F(_:! type where .Self impls (Z where .Z1 = {})) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_todo_rewrite_provided_by_named_constraint.carbon:[[@LINE-13]]:6: note: initializing generic parameter `_` declared here [InitializingGenericParam] + // CHECK:STDERR: fn F(_:! Z where .Z1 = {}) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: F(T); } -// --- fail_todo_rewrite_in_impls_provided_by_named_constraint.carbon +// --- fail_rewrite_not_provided_by_named_constraint_without_extend.carbon library "[[@TEST_NAME]]"; interface Z { let Z1:! type; } -fn F(_:! type where .Self impls (Z where .Z1 = {})) {} +fn F(_:! Z where .Z1 = {}) {} constraint N { + // Without extend, this does not actually rewrite `.Z1 = {}`, it provides the + // equivalent of `.Z1 == {}` which allows conversion of `.Z1` to `{}` but is + // not enough to satisfy the requirement of `F` that `.Z1` is rewritten to + // `{}`. require impls Z where .Z1 = {}; } fn G(T:! N) { - // CHECK:STDERR: fail_todo_rewrite_in_impls_provided_by_named_constraint.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `N` into type implementing `type where .Self impls Z and .(Z.Z1) = {}` [ConversionFailureFacetToFacet] + // CHECK:STDERR: fail_rewrite_not_provided_by_named_constraint_without_extend.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `N` into type implementing `Z where .(Z.Z1) = {}` [ConversionFailureFacetToFacet] // CHECK:STDERR: F(T); // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_todo_rewrite_in_impls_provided_by_named_constraint.carbon:[[@LINE-10]]:6: note: initializing generic parameter `_` declared here [InitializingGenericParam] - // CHECK:STDERR: fn F(_:! type where .Self impls (Z where .Z1 = {})) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_rewrite_not_provided_by_named_constraint_without_extend.carbon:[[@LINE-14]]:6: note: initializing generic parameter `_` declared here [InitializingGenericParam] + // CHECK:STDERR: fn F(_:! Z where .Z1 = {}) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: F(T); } + +// CHECK:STDOUT: --- rewrite_provided_by_facet_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Z.type: type = facet_type <@Z> [concrete] +// CHECK:STDOUT: %.Self.94e: %Z.type = symbolic_binding .Self [symbolic_self] +// CHECK:STDOUT: %Z.lookup_impl_witness.e2b: = lookup_impl_witness %.Self.94e, @Z [symbolic_self] +// CHECK:STDOUT: %impl.elem0: type = impl_witness_access %Z.lookup_impl_witness.e2b, element0 [symbolic_self] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %Z_where.type.767: type = facet_type <@Z where %impl.elem0 = %empty_struct_type> [concrete] +// CHECK:STDOUT: %F.type: type = fn_type @F [concrete] +// CHECK:STDOUT: %F: %F.type = struct_value () [concrete] +// CHECK:STDOUT: %impl.elem1: type = impl_witness_access %Z.lookup_impl_witness.e2b, element1 [symbolic_self] +// CHECK:STDOUT: %Z_where.type.a88: type = facet_type <@Z where %impl.elem0 = %empty_struct_type and %impl.elem1 = %empty_struct_type> [concrete] +// CHECK:STDOUT: %pattern_type.d22: type = pattern_type %Z_where.type.a88 [concrete] +// CHECK:STDOUT: %T.patt: %pattern_type.d22 = symbolic_binding_pattern T, 0 [symbolic] +// CHECK:STDOUT: %T: %Z_where.type.a88 = symbolic_binding T, 0 [symbolic] +// CHECK:STDOUT: %T.as_type: type = facet_access_type %T [symbolic] +// CHECK:STDOUT: %Z.lookup_impl_witness.d70: = lookup_impl_witness %T, @Z [symbolic] +// CHECK:STDOUT: %facet_value: %Z_where.type.767 = facet_value %T.as_type, (%Z.lookup_impl_witness.d70) [symbolic] +// CHECK:STDOUT: %F.specific_fn: = specific_function %F, @F(%facet_value) [symbolic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @G(%T.loc10_7.2: %Z_where.type.a88) { +// CHECK:STDOUT: +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %T.as_type.loc14_6.2: type = facet_access_type %T.loc10_7.1 [symbolic = %T.as_type.loc14_6.2 (constants.%T.as_type)] +// CHECK:STDOUT: %Z.lookup_impl_witness: = lookup_impl_witness %T.loc10_7.1, @Z [symbolic = %Z.lookup_impl_witness (constants.%Z.lookup_impl_witness.d70)] +// CHECK:STDOUT: %facet_value.loc14_6.2: %Z_where.type.767 = facet_value %T.as_type.loc14_6.2, (%Z.lookup_impl_witness) [symbolic = %facet_value.loc14_6.2 (constants.%facet_value)] +// CHECK:STDOUT: %F.specific_fn.loc14_3.2: = specific_function constants.%F, @F(%facet_value.loc14_6.2) [symbolic = %F.specific_fn.loc14_3.2 (constants.%F.specific_fn)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [concrete = constants.%F] +// CHECK:STDOUT: %T.ref: %Z_where.type.a88 = name_ref T, %T.loc10_7.2 [symbolic = %T.loc10_7.1 (constants.%T)] +// CHECK:STDOUT: %T.as_type.loc14_6.1: type = facet_access_type %T.ref [symbolic = %T.as_type.loc14_6.2 (constants.%T.as_type)] +// CHECK:STDOUT: %facet_value.loc14_6.1: %Z_where.type.767 = facet_value %T.as_type.loc14_6.1, (constants.%Z.lookup_impl_witness.d70) [symbolic = %facet_value.loc14_6.2 (constants.%facet_value)] +// CHECK:STDOUT: %.loc14: %Z_where.type.767 = converted %T.ref, %facet_value.loc14_6.1 [symbolic = %facet_value.loc14_6.2 (constants.%facet_value)] +// CHECK:STDOUT: %F.specific_fn.loc14_3.1: = specific_function %F.ref, @F(constants.%facet_value) [symbolic = %F.specific_fn.loc14_3.2 (constants.%F.specific_fn)] +// CHECK:STDOUT: %F.call: init %empty_tuple.type = call %F.specific_fn.loc14_3.1() +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @G(constants.%T) { +// CHECK:STDOUT: %T.patt.loc10_7.2 => constants.%T.patt +// CHECK:STDOUT: %T.loc10_7.1 => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/impl_assoc_const.carbon b/toolchain/check/testdata/impl/impl_assoc_const.carbon index f6ab83a4d148..1de05a124d3b 100644 --- a/toolchain/check/testdata/impl/impl_assoc_const.carbon +++ b/toolchain/check/testdata/impl/impl_assoc_const.carbon @@ -341,8 +341,11 @@ impl CD as IF where .F = 0 { library "[[@TEST_NAME]]"; interface M { let X:! type; } +constraint N { + extend require impls M where .X = {}; +} -impl () as M where .X = (M where .X = (M where .X = {})) {} +impl () as M where .X = N {} // --- fail_todo_period_self_impl_lookup.carbon library "[[@TEST_NAME]]"; diff --git a/toolchain/check/testdata/impl/impl_where_redecl.carbon b/toolchain/check/testdata/impl/impl_where_redecl.carbon index 5fd4fa9ad5da..3bfbd10747ca 100644 --- a/toolchain/check/testdata/impl/impl_where_redecl.carbon +++ b/toolchain/check/testdata/impl/impl_where_redecl.carbon @@ -16,45 +16,47 @@ library "[[@TEST_NAME]]"; interface I { let T:! type; } +constraint N(U:! type) {} // CHECK:STDERR: fail_match_with_associated_type.carbon:[[@LINE+4]]:1: error: impl declared but not defined [ImplMissingDefinition] // CHECK:STDERR: impl () as I where .T = {}; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: impl () as I where .T = {}; -impl () as I where .T = {} and .T impls (type where .Self impls type) {} +impl () as I where .T = {} and .T impls N(.Self) {} // CHECK:STDERR: fail_match_with_associated_type.carbon:[[@LINE+4]]:1: error: impl declared but not defined [ImplMissingDefinition] // CHECK:STDERR: impl {} as I; // CHECK:STDERR: ^~~~~~~~~~~~~ // CHECK:STDERR: impl {} as I; -impl {} as I where .T = {} and .T impls (type where .Self impls type) {} +impl {} as I where .T = {} and .T impls N(.Self) {} // CHECK:STDERR: fail_match_with_associated_type.carbon:[[@LINE+4]]:1: error: impl declared but not defined [ImplMissingDefinition] -// CHECK:STDERR: impl ({},) as I where .T = {} and .T impls (type where .Self impls type); -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: impl ({},) as I where .T = {} and .T impls N(.Self); +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: -impl ({},) as I where .T = {} and .T impls (type where .Self impls type); +impl ({},) as I where .T = {} and .T impls N(.Self); impl ({},) as I where .T = {} {} // --- fail_match_with_empty_interface.carbon library "[[@TEST_NAME]]"; interface J {} +constraint N {} // CHECK:STDERR: fail_match_with_empty_interface.carbon:[[@LINE+4]]:1: error: impl declared but not defined [ImplMissingDefinition] // CHECK:STDERR: impl () as J; // CHECK:STDERR: ^~~~~~~~~~~~~ // CHECK:STDERR: impl () as J; -impl () as J where .Self impls type and .Self impls (type where .Self impls type) {} +impl () as J where .Self impls type and .Self impls N {} // CHECK:STDERR: fail_match_with_empty_interface.carbon:[[@LINE+4]]:1: error: impl declared but not defined [ImplMissingDefinition] -// CHECK:STDERR: impl {} as J where .Self impls type and .Self impls (type where .Self impls type); -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: impl {} as J where .Self impls type and .Self impls N; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: -impl {} as J where .Self impls type and .Self impls (type where .Self impls type); +impl {} as J where .Self impls type and .Self impls N; impl {} as J {} // --- fail_parens_other_nesting.carbon diff --git a/toolchain/check/testdata/impl/lookup/access.carbon b/toolchain/check/testdata/impl/lookup/access.carbon index bcac443b1c32..654ca57e17c6 100644 --- a/toolchain/check/testdata/impl/lookup/access.carbon +++ b/toolchain/check/testdata/impl/lookup/access.carbon @@ -10,7 +10,7 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/lookup/access.carbon -// --- impl_witness_access_in_impl_type_structure.carbon +// --- fail_todo_impl_witness_access_in_impl_type_structure.carbon library "[[@TEST_NAME]]"; interface X(T:! type) {} @@ -25,11 +25,11 @@ interface Z { // resolve to a symbolic type value, so the type structure is: `? as X(?)` impl forall [T:! Z where .Z1 impls Y] T as X(T.Z1.(Y.Y1)) {} -class C { - impl as Y where .Y1 = {} {} +class C(W:! type) { + impl as Y where .Y1 = W {} } -fn F(V:! Z where .Z1 = C) { +fn F(V:! Z where .Z1 = C({})) { // The type stucture is `? as X({})` which will match the impl's less specific // `? as X(?)`, then the impl will deduce the parameter of `X` to be `{}` from // the type of `V`. This would fail if ImplWitnessAccess instructions were @@ -45,11 +45,17 @@ fn G(V:! Z where .Z1 impls Y) { V as X(V.(Z.Z1).(Y.Y1)); } -fn H(U:! type, V:! Z where .Z1 impls (Y where .Y1 = U)) { +fn H(U:! type, V:! Z where .Z1 = C(U)) { // The type structure is `? as X(?)`, without using an ImplWitnessAccess, // which will match the impl's `? as X(?)`. This would fail if // ImplWitnessAccess instructions were treated as Concrete in the type // structure, since the impl's type structure would be more specific than the // query's. + // + // TODO: This should pass. + // CHECK:STDERR: fail_todo_impl_witness_access_in_impl_type_structure.carbon:[[@LINE+4]]:3: error: cannot convert type `V` that implements `Z where .(Z.Z1) = C(U)` into type implementing `X(U)` [ConversionFailureFacetToFacet] + // CHECK:STDERR: V as X(U); + // CHECK:STDERR: ^~~~~~~~~ + // CHECK:STDERR: V as X(U); } diff --git a/toolchain/check/testdata/where_expr/designator.carbon b/toolchain/check/testdata/where_expr/designator.carbon index 3407e2bee6c3..921b07af8848 100644 --- a/toolchain/check/testdata/where_expr/designator.carbon +++ b/toolchain/check/testdata/where_expr/designator.carbon @@ -143,142 +143,6 @@ fn F(unused T:! type where C(.Self) impls I(())) {} fn G(unused T:! type where C(()) impls I(.Self)) {} -// --- fail_impls_with_nested_facet_type_with_rewrite_does_not_constrain_self.carbon -library "[[@TEST_NAME]]"; - -interface I { - let I1:! type; -} -class C; - -// The `.I1` satisfies constraining the "current type" of the inner nested facet -// type `I where ...`. But it does not constrain the current type of the outer -// facet type `type where...`. We should not consider the designator in the -// nested where expression as making the `C impls ...` constraint valid. - -// CHECK:STDERR: fail_impls_with_nested_facet_type_with_rewrite_does_not_constrain_self.carbon:[[@LINE+4]]:29: error: constraint in `where` clause without a designator; expected `.Self` or a member access like `.M` [WhereWithoutDesignator] -// CHECK:STDERR: fn F1(unused T:! type where C impls (I where .I1 = C)) {} -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: -fn F1(unused T:! type where C impls (I where .I1 = C)) {} - -// --- fail_impls_with_nested_facet_type_with_equiv_does_not_constrain_self.carbon -library "[[@TEST_NAME]]"; - -interface I { - let I1:! type; -} -class C; - -// The `.I1` satisfies constraining the "current type" of the inner nested facet -// type `I where ...`. But it does not constrain the current type of the outer -// facet type `type where...`. We should not consider the designator in the -// nested where expression as making the `C impls ...` constraint valid. - -// CHECK:STDERR: fail_impls_with_nested_facet_type_with_equiv_does_not_constrain_self.carbon:[[@LINE+4]]:29: error: constraint in `where` clause without a designator; expected `.Self` or a member access like `.M` [WhereWithoutDesignator] -// CHECK:STDERR: fn F2(unused T:! type where C impls (I where .I1 == C)) {} -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: -fn F2(unused T:! type where C impls (I where .I1 == C)) {} - -// --- fail_impls_with_nested_facet_type_with_impls_does_not_constrain_self.carbon -library "[[@TEST_NAME]]"; - -interface I { - let I1:! type; -} -interface J(T:! type) {} -class C; - -// The `.I1` satisfies constraining the "current type" of the inner nested facet -// type `I where ...`. But it does not constrain the current type of the outer -// facet type `type where...`. We should not consider the designator in the -// nested where expression as making the `C impls ...` constraint valid. - -// CHECK:STDERR: fail_impls_with_nested_facet_type_with_impls_does_not_constrain_self.carbon:[[@LINE+4]]:29: error: constraint in `where` clause without a designator; expected `.Self` or a member access like `.M` [WhereWithoutDesignator] -// CHECK:STDERR: fn F3(unused T:! type where C impls (I where .I1 impls J(.Self))) {} -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: -fn F3(unused T:! type where C impls (I where .I1 impls J(.Self))) {} - -// --- fail_equiv_with_nested_facet_type_with_rewrite_does_not_constrain_self.carbon -library "[[@TEST_NAME]]"; - -interface I { - let I1:! type; -} -class C; - -// The `.I1` satisfies constraining the "current type" of the inner nested facet -// type `I where ...`. But it does not constrain the current type of the outer -// facet type `I where...`. We should not consider the designator in the nested -// where expression as making the `C impls ...` constraint valid. - -// CHECK:STDERR: fail_equiv_with_nested_facet_type_with_rewrite_does_not_constrain_self.carbon:[[@LINE+4]]:28: error: constraint in `where` clause without a designator; expected `.Self` or a member access like `.M` [WhereWithoutDesignator] -// CHECK:STDERR: fn F(unused T:! type where C == (I where .I1 = C)) {} -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: -fn F(unused T:! type where C == (I where .I1 = C)) {} - -// --- fail_equiv_with_nested_facet_type_with_equiv_does_not_constrain_self.carbon -library "[[@TEST_NAME]]"; - -interface I { - let I1:! type; -} -class C; - -// The `.I1` satisfies constraining the "current type" of the inner nested facet -// type `I where ...`. But it does not constrain the current type of the outer -// facet type `I where...`. We should not consider the designator in the nested -// where expression as making the `C impls ...` constraint valid. - -// CHECK:STDERR: fail_equiv_with_nested_facet_type_with_equiv_does_not_constrain_self.carbon:[[@LINE+4]]:28: error: constraint in `where` clause without a designator; expected `.Self` or a member access like `.M` [WhereWithoutDesignator] -// CHECK:STDERR: fn F(unused T:! type where C == (I where .I1 == C)) {} -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: -fn F(unused T:! type where C == (I where .I1 == C)) {} - -// --- fail_equiv_with_nested_facet_type_with_impls_does_not_constrain_self.carbon -library "[[@TEST_NAME]]"; - -interface I { - let I1:! type; -} -interface J(T:! type) {} -class C; - -// The `.I1` satisfies constraining the "current type" of the inner nested facet -// type `I where ...`. But it does not constrain the current type of the outer -// facet type `I where...`. We should not consider the designator in the nested -// where expression as making the `C impls ...` constraint valid. - -// CHECK:STDERR: fail_equiv_with_nested_facet_type_with_impls_does_not_constrain_self.carbon:[[@LINE+4]]:28: error: constraint in `where` clause without a designator; expected `.Self` or a member access like `.M` [WhereWithoutDesignator] -// CHECK:STDERR: fn F(unused T:! type where C == (I where .I1 impls J(.Self))) {} -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: -fn F(unused T:! type where C == (I where .I1 impls J(.Self))) {} - -// --- fail_impls_with_nested_facet_type_does_not_constrain_self.carbon -library "[[@TEST_NAME]]"; - -interface I { - let I1:! type; -} -interface J(T:! type) {} -class C; - -// The `.I1` satisfies constraining the "current type" of the inner nested facet -// type `I where ...`. But it does not constrain the current type of the outer -// facet type `I where...`. We should not consider the designator in the nested -// where expression as making the `(I where ...) impls ...` constraint valid. - -// CHECK:STDERR: fail_impls_with_nested_facet_type_does_not_constrain_self.carbon:[[@LINE+4]]:28: error: constraint in `where` clause without a designator; expected `.Self` or a member access like `.M` [WhereWithoutDesignator] -// CHECK:STDERR: fn F(unused T:! type where (I where .I1 impls J(.Self)) impls I) {} -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: -fn F(unused T:! type where (I where .I1 impls J(.Self)) impls I) {} - // --- fail_where_without_designator_in_one_equiv_constraint.carbon library "[[@TEST_NAME]]"; @@ -304,51 +168,107 @@ interface Z { // CHECK:STDERR: fn G(unused T:! Z where A(.Z0) == B and A(B) == B) {} -// --- fail_where_without_designator_in_one_impls_interface.carbon +// --- fail_where_without_self_designator_in_one_impls_interface.carbon library "[[@TEST_NAME]]"; +interface Z(T:! type) {} interface I {} interface J(T:! type) {} class C; -// CHECK:STDERR: fail_where_without_designator_in_one_impls_interface.carbon:[[@LINE+4]]:28: error: constraint in `where` clause without a designator; expected `.Self` or a member access like `.M` [WhereWithoutDesignator] +// CHECK:STDERR: fail_where_without_self_designator_in_one_impls_interface.carbon:[[@LINE+4]]:28: error: constraint in `where` clause without a designator; expected `.Self` or a member access like `.M` [WhereWithoutDesignator] // CHECK:STDERR: fn F(unused T:! type where C impls (I & J(.Self))) {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: fn F(unused T:! type where C impls (I & J(.Self))) {} -interface Z { - let Z0:! type; -} - -// CHECK:STDERR: fail_where_without_designator_in_one_impls_interface.carbon:[[@LINE+4]]:25: error: constraint in `where` clause without a designator; expected `.Self` or a member access like `.M` [WhereWithoutDesignator] -// CHECK:STDERR: fn G(unused T:! Z where C impls (I & J(.Z0))) {} -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: -fn G(unused T:! Z where C impls (I & J(.Z0))) {} - -// --- fail_where_without_designator_in_one_impls_named_constraint.carbon +// --- fail_where_without_member_designator_in_one_impls_interface.carbon library "[[@TEST_NAME]]"; -constraint I {} -constraint J(T:! type) {} +interface Z { + let Z0:! type; +} +interface I {} +interface J(T:! type) {} class C; -// CHECK:STDERR: fail_where_without_designator_in_one_impls_named_constraint.carbon:[[@LINE+4]]:28: error: constraint in `where` clause without a designator; expected `.Self` or a member access like `.M` [WhereWithoutDesignator] -// CHECK:STDERR: fn F(unused T:! type where C impls (I & J(.Self))) {} +// CHECK:STDERR: fail_where_without_member_designator_in_one_impls_interface.carbon:[[@LINE+4]]:25: error: constraint in `where` clause without a designator; expected `.Self` or a member access like `.M` [WhereWithoutDesignator] +// CHECK:STDERR: fn F(unused T:! Z where C impls (I & J(.Z0))) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn F(unused T:! Z where C impls (I & J(.Z0))) {} + +// --- fail_where_without_self_designator_in_one_impls_named_constraint.carbon +library "[[@TEST_NAME]]"; + +interface Z {} +constraint I {} +interface J(T:! type) {} +constraint K(T:! type) { + require T impls J(Self); +} +class C; + +// CHECK:STDERR: fail_where_without_self_designator_in_one_impls_named_constraint.carbon:[[@LINE+4]]:28: error: constraint in `where` clause without a designator; expected `.Self` or a member access like `.M` [WhereWithoutDesignator] +// CHECK:STDERR: fn F(unused T:! type where C impls (I & K(.Self))) {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: -fn F(unused T:! type where C impls (I & J(.Self))) {} +fn F(unused T:! type where C impls (I & K(.Self))) {} + +// --- fail_where_without_member_designator_in_one_impls_named_constraint.carbon +library "[[@TEST_NAME]]"; interface Z { let Z0:! type; } +constraint I {} +interface J(T:! type) {} +constraint K(T:! type) { + require T impls J(Self); +} +class C; -// CHECK:STDERR: fail_where_without_designator_in_one_impls_named_constraint.carbon:[[@LINE+4]]:25: error: constraint in `where` clause without a designator; expected `.Self` or a member access like `.M` [WhereWithoutDesignator] -// CHECK:STDERR: fn G(unused T:! Z where C impls (I & J(.Z0))) {} + +// CHECK:STDERR: fail_where_without_member_designator_in_one_impls_named_constraint.carbon:[[@LINE+4]]:25: error: constraint in `where` clause without a designator; expected `.Self` or a member access like `.M` [WhereWithoutDesignator] +// CHECK:STDERR: fn F(unused T:! Z where C impls (I & K(.Z0))) {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: -fn G(unused T:! Z where C impls (I & J(.Z0))) {} +fn F(unused T:! Z where C impls (I & K(.Z0))) {} + +// --- constraint_does_constrain_designator_as_self.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) {} +constraint N(T:! type) { + require T impls Z(Self); +} +class C; + +fn F(unused T:! type where C impls N(.Self)) {} + +// --- constraint_does_constrain_designator_as_specific.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) {} +constraint N(T:! type) { + require impls Z(T); +} +class C; + +fn F(unused T:! type where C impls N(.Self)) {} + +// --- todo_fail_constraint_does_not_constrain_designator.carbon +library "[[@TEST_NAME]]"; + +interface Z {} +constraint N(T:! type) { + require impls Z; +} +class C; + +// TODO: This `.Self` is not actually constrained by `C impls N(.Self)`, so it +// should fail. +fn F(unused T:! type where C impls N(.Self)) {} // CHECK:STDOUT: --- success.carbon // CHECK:STDOUT: diff --git a/toolchain/check/testdata/where_expr/dot_self_impls.carbon b/toolchain/check/testdata/where_expr/dot_self_impls.carbon index c00b86347512..8413ba7777df 100644 --- a/toolchain/check/testdata/where_expr/dot_self_impls.carbon +++ b/toolchain/check/testdata/where_expr/dot_self_impls.carbon @@ -162,19 +162,13 @@ fn Test() { AssertSame(Type(I & J where .Self impls K), Type(J & I where .Self impls J & K)); AssertSame(Type(I & J where .Self impls K), Type(J & I where .Self impls K & I & J)); AssertSame(Type(I where .Self impls J & K), Type(I where .Self impls K & I & J)); - AssertSame(Type(I where .Self impls J & K), - Type(I where .Self impls (J where .Self impls K))); - AssertSame(Type(I where .Self impls J & K), - Type(I where .Self impls (K where .Self impls J))); - AssertSame(Type(I where .Self impls J & K), - Type(I where .Self impls (type where .Self impls (J where .Self impls K)))); } interface I {} interface J {} interface K {} -// --- compare_equal_with_associated_constant.carbon +// --- fail_todo_compare_equal_with_rewrite.carbon library "[[@TEST_NAME]]"; class WrapType(T:! type) {} @@ -182,19 +176,48 @@ fn AssertSame[T:! type](unused a: WrapType(T), unused b: WrapType(T)) {} fn Type(T:! type) -> WrapType(T) { return {}; } interface I { let A:! type; } -interface J { let A:! type; } +interface J { let B:! type; } + +// TODO: The `.Self` implied in `.A` contains all of the extended interfaces, +// which is different between these facet types at the point where `.A` is +// written. So the resulting facet types are different. We should drop +// interfaces from the rewrite constraint's LHS that don't apply so that we get +// a canonical representation of `.A` that is independent of the current state +// of `.Self` since `.A = ()` can not be written as, and is thus not equivalent +// to, `.Self.(I.A) = ()`. fn Test() { + // TODO: This should pass. + // CHECK:STDERR: fail_todo_compare_equal_with_rewrite.carbon:[[@LINE+7]]:3: error: inconsistent deductions for value of generic parameter `T` [DeductionInconsistent] + // CHECK:STDERR: AssertSame(Type((I where .A = ()) & J), + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_todo_compare_equal_with_rewrite.carbon:[[@LINE-19]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn AssertSame[T:! type](unused a: WrapType(T), unused b: WrapType(T)) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: AssertSame(Type((I where .A = ()) & J), - Type(I & J where .Self impls (I where .A = ()))); - AssertSame(Type(I & (J where .A = {})), - Type(I & J where .Self impls (J where .A = {}))); + Type(I & J where .A = ())); + // TODO: This should pass. + // CHECK:STDERR: fail_todo_compare_equal_with_rewrite.carbon:[[@LINE+7]]:3: error: inconsistent deductions for value of generic parameter `T` [DeductionInconsistent] + // CHECK:STDERR: AssertSame(Type(I & (J where .B = {})), + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_todo_compare_equal_with_rewrite.carbon:[[@LINE-29]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn AssertSame[T:! type](unused a: WrapType(T), unused b: WrapType(T)) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + AssertSame(Type(I & (J where .B = {})), + Type(I & J where .B = {})); - AssertSame(Type((I where .A = ()) & (J where .A = {})), - Type(I & J where .Self impls (I where .A = ()) - and .Self impls (J where .A = {}))); - AssertSame(Type((I where .A = ()) & (J where .A = {})), - Type(I & J where .Self impls (I where .A = ()) & (J where .A = {}))); + // TODO: This should pass. + // CHECK:STDERR: fail_todo_compare_equal_with_rewrite.carbon:[[@LINE+7]]:3: error: inconsistent deductions for value of generic parameter `T` [DeductionInconsistent] + // CHECK:STDERR: AssertSame(Type((I where .A = ()) & (J where .B = {})), + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_todo_compare_equal_with_rewrite.carbon:[[@LINE-40]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn AssertSame[T:! type](unused a: WrapType(T), unused b: WrapType(T)) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + AssertSame(Type((I where .A = ()) & (J where .B = {})), + Type(I & J where .A = () and .B = {})); } // --- fail_compare_not_equal.carbon @@ -218,6 +241,25 @@ fn Test() { Same(Type(I where .Self impls J), Type(J where .Self impls I)); } +// --- todo_fail_compare_not_equal_with_same_type.carbon +library "[[@TEST_NAME]]"; + +class WrapType(T:! type) {} +fn Same[T:! type](unused a: WrapType(T), unused b: WrapType(T)) {} +fn Type(T:! type) -> WrapType(T) { return {}; } + +interface I { let A:! type; } +interface J { let B:! type; } + +fn Test() { + // The first `.A` has a `.Self` of type `I`. The second contains a `.Self` of + // type `I & J`. That makes the two constaints `.A == ()` have different + // constant values, so these are different facet types. + // + // TODO: This should fail. We don't store same-type constraints in the facet type yet. + Same(Type((I where .A == ()) & J), Type(I & J where .A == ())); +} + // --- impl_as.carbon library "[[@TEST_NAME]]"; @@ -233,9 +275,6 @@ interface J { let T:! type; } impl {.a: C} as I where .Self impls J {} impl {.b: C} as J where .Self impls I and .T = () {} -// Rewrite constraints can appear inside the `where .Self impls`. -impl {.c: C} as J where .Self impls (I & J where .T = ()) {} - // --- impl_with_rewrite_of_interface_not_being_implemented.carbon library "[[@TEST_NAME]]"; @@ -247,12 +286,16 @@ class C {} // Implementation of `C as J`. impl C as J where .A = {} {} +// Requirement of implementing J with `.A = A`. +constraint NeedJ(A:! type) { + require impls J where .A = A; +} + // This is an implementation of `I` with `I.A = ()`. The requirement // that `C` also impls `J where .A = {}` is an additional constraint // that must be satisfied (and is satisfied by the impl above, though // that currently isn't checked), but doesn't affect `C as I`. -impl C as I where .Self impls - (J where .A = {} and .Self impls (I where .A = ())) {} +impl C as I where .A = () and .Self impls NeedJ({}) {} let x: C.(I.A) = (); let y: C.(J.A) = {}; diff --git a/toolchain/diagnostics/kind.def b/toolchain/diagnostics/kind.def index 7e9ebc7f9384..0a48d0212ea6 100644 --- a/toolchain/diagnostics/kind.def +++ b/toolchain/diagnostics/kind.def @@ -192,7 +192,8 @@ CARBON_DIAGNOSTIC_KIND(ExpectedAliasInitializer) // Where requirement diagnostics. CARBON_DIAGNOSTIC_KIND(ExpectedRequirementOperator) CARBON_DIAGNOSTIC_KIND(RequirementEqualAfterNonDesignator) -CARBON_DIAGNOSTIC_KIND(AmbiguousPeriodSelf) +CARBON_DIAGNOSTIC_KIND(NestedWhereInsideWhere) +CARBON_DIAGNOSTIC_KIND(NestedWhereInsideWhereOuterNote) // ============================================================================ // Semantics diagnostics