Forbid nested where inside a where expression (#7378)

This disallows building a facet type that contains another facet type
with non-extend constraints in it. Which in turn prevents the
possibility of introducing a different `.Self` into a facet type.

Eval can still insert a facet type with non-extend constraints, as we
only prevent it for `where` being written into the facet type. There is
a TODO in handle_where.cpp for this and some tests in
toolchain/check/testdata/facet/nested_facet_types_from_eval.carbon
This commit is contained in:
Dana Jansens
2026-06-25 18:56:36 +00:00
committed by GitHub
parent 093dc04db6
commit b22ee48c9b
19 changed files with 671 additions and 1151 deletions
+2
View File
@@ -278,6 +278,8 @@ class Context {
SemIR::ConstantId facet_type_const_id;
};
llvm::SmallVector<SelfImplsFacetType> impls;
SemIR::LocId loc_id;
};
auto where_stack() -> llvm::SmallVector<WhereStackEntry>& {
+4
View File
@@ -3243,6 +3243,10 @@ auto TryEvalTypedInst<SemIR::WhereExpr>(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.
+27 -8
View File
@@ -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<SemIR::RequirementImpls>(
@@ -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<SemIR::WhereExpr>(
context, node_id,
{.type_id = SemIR::TypeType::TypeId, .requirements_id = requirements_id});
{.type_id = type_id, .requirements_id = requirements_id});
return true;
}
-316
View File
@@ -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<SemIR::FacetType>(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<SemIR::NameRef>(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<SemIR::FacetType>(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<SemIR::ImplWitnessAccess>(
const_inst_id)) {
if (auto lookup = context().insts().TryGetAs<SemIR::LookupImplWitness>(
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 `<type> "
"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<WorkItem> work;
if (auto where_expr =
context.insts().TryGetAs<SemIR::WhereExpr>(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<SemIR::FacetType>(
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
-15
View File
@@ -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_
+20 -69
View File
@@ -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: ^~~~~~~~~~
+13 -5
View File
@@ -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))) {}
+36 -16
View File
@@ -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:
+69 -7
View File
@@ -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)) {}
@@ -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) {}
-170
View File
@@ -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 `<type> 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 `<type> 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 `<type> 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 `<type> 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]]";
@@ -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]]";
@@ -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: <witness> = 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: <witness> = 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> = 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: <elided>
// 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: <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> = 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> = 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: <elided>
// 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:
+4 -1
View File
@@ -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]]";
+11 -9
View File
@@ -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
+11 -5
View File
@@ -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);
}
+77 -157
View File
@@ -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:
+64 -21
View File
@@ -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) = {};
+2 -1
View File
@@ -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