mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 19:10:14 +01:00
Identify and complete facet types as needed for p5168 (#6369)
Proposal #5168 defines when a facet type must be identified or complete, and what it means for an interface and a named constraint to be identified or complete. This updates the toolchain to match the requirements. This implements identification of a facet type to require completed named constraints and to include any interfaces from named constraints into the resulting IdentifiedFacetType. To complete a facet type, each interface in the IdentifiedFacetType, and any interface named though a require declaration from them, must be complete.
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#include "toolchain/check/subst.h"
|
||||
#include "toolchain/check/type.h"
|
||||
#include "toolchain/check/type_completion.h"
|
||||
#include "toolchain/diagnostics/diagnostic.h"
|
||||
#include "toolchain/parse/node_ids.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/named_constraint.h"
|
||||
@@ -81,6 +82,15 @@ auto HandleParseNode(Context& context, Parse::RequireDefaultSelfImplsId node_id)
|
||||
auto HandleParseNode(Context& context, Parse::RequireTypeImplsId node_id)
|
||||
-> bool {
|
||||
auto [self_node_id, self_inst_id] = context.node_stack().PopExprWithNodeId();
|
||||
|
||||
auto introducer = context.decl_introducer_state_stack().innermost();
|
||||
if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) {
|
||||
CARBON_DIAGNOSTIC(RequireImplsExtendWithExplicitSelf, Error,
|
||||
"`extend require impls` with explicit type");
|
||||
context.emitter().Emit(self_node_id, RequireImplsExtendWithExplicitSelf);
|
||||
self_inst_id = SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
auto self_type = ExprAsType(context, self_node_id, self_inst_id);
|
||||
context.node_stack().Push(node_id, self_type.inst_id);
|
||||
return true;
|
||||
@@ -241,6 +251,8 @@ auto HandleParseNode(Context& context, Parse::RequireDeclId node_id) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool extend = introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend);
|
||||
|
||||
auto require_impls_decl =
|
||||
SemIR::RequireImplsDecl{// To be filled in after.
|
||||
.require_impls_id = SemIR::RequireImplsId::None,
|
||||
@@ -251,6 +263,7 @@ auto HandleParseNode(Context& context, Parse::RequireDeclId node_id) -> bool {
|
||||
.facet_type_inst_id =
|
||||
context.types().GetAsTypeInstId(constraint_inst_id),
|
||||
.facet_type_id = constraint_facet_type.facet_type_id,
|
||||
.extend_self = extend,
|
||||
.decl_id = decl_id,
|
||||
.parent_scope_id = context.scope_stack().PeekNameScopeId(),
|
||||
.generic_id = BuildGenericDecl(context, decl_id)});
|
||||
|
||||
@@ -121,6 +121,7 @@ auto ImplWitnessStartDefinition(Context& context, SemIR::Impl& impl) -> void {
|
||||
witness_block.empty()) {
|
||||
if (!RequireCompleteFacetTypeForImplDefinition(
|
||||
context, SemIR::LocId(impl.latest_decl_id()), impl.constraint_id)) {
|
||||
FillImplWitnessWithErrors(context, impl);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -203,10 +203,10 @@ static auto GetInterfacesFromConstantId(
|
||||
context.facet_types().Get(facet_type_inst.facet_type_id);
|
||||
auto identified_id =
|
||||
RequireIdentifiedFacetType(context, facet_type_inst, [&] {
|
||||
CARBON_DIAGNOSTIC(ImplLookupInIncompleteFacetType, Error,
|
||||
"facet type {0} is incomplete", InstIdAsType);
|
||||
return context.emitter().Build(loc_id, ImplLookupInIncompleteFacetType,
|
||||
facet_type_inst_id);
|
||||
CARBON_DIAGNOSTIC(ImplLookupInUnidentifiedFacetType, Error,
|
||||
"facet type {0} can not be identified", InstIdAsType);
|
||||
return context.emitter().Build(
|
||||
loc_id, ImplLookupInUnidentifiedFacetType, facet_type_inst_id);
|
||||
});
|
||||
if (!identified_id.has_value()) {
|
||||
return std::nullopt;
|
||||
|
||||
@@ -2468,6 +2468,7 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
|
||||
resolver.local_insts().GetAs<SemIR::FacetType>(
|
||||
new_canonical_facet_type_inst_id);
|
||||
new_require.facet_type_id = new_canonical_facet_type.facet_type_id;
|
||||
new_require.extend_self = import_require.extend_self;
|
||||
new_require.parent_scope_id = parent_scope_id;
|
||||
|
||||
SetGenericData(resolver, import_require.generic_id, new_require.generic_id,
|
||||
|
||||
+99
-80
@@ -2,7 +2,7 @@
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/convert.carbon
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/none.carbon
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
@@ -13,95 +13,114 @@
|
||||
// --- fail_incomplete_interface.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
interface A;
|
||||
interface B {}
|
||||
interface X;
|
||||
class C {}
|
||||
|
||||
fn G[T:! A](t: T) {}
|
||||
fn H[T:! A & B](t: T) {}
|
||||
// Requires X identified.
|
||||
impl C as X;
|
||||
|
||||
fn F() {
|
||||
// CHECK:STDERR: fail_incomplete_interface.carbon:[[@LINE+4]]:3: error: cannot convert type `C` into type implementing `A` [ConversionFailureTypeToFacet]
|
||||
// CHECK:STDERR: C as A;
|
||||
// CHECK:STDERR: ^~~~~~
|
||||
// CHECK:STDERR:
|
||||
C as A;
|
||||
// Requires X complete.
|
||||
// CHECK:STDERR: fail_incomplete_interface.carbon:[[@LINE+7]]:1: error: definition of impl as incomplete facet type `X` [ImplAsIncompleteFacetTypeDefinition]
|
||||
// CHECK:STDERR: impl C as X {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_incomplete_interface.carbon:[[@LINE-10]]:1: note: interface was forward declared here [InterfaceForwardDeclaredHere]
|
||||
// CHECK:STDERR: interface X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
impl C as X {}
|
||||
|
||||
// CHECK:STDERR: fail_incomplete_interface.carbon:[[@LINE+4]]:3: error: cannot convert type `C` into type implementing `A & B` [ConversionFailureTypeToFacet]
|
||||
// CHECK:STDERR: C as (A & B);
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
C as (A & B);
|
||||
|
||||
// CHECK:STDERR: fail_incomplete_interface.carbon:[[@LINE+7]]:3: error: cannot convert type `C` into type implementing `A` [ConversionFailureTypeToFacet]
|
||||
// CHECK:STDERR: G({} as C);
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
// CHECK:STDERR: fail_incomplete_interface.carbon:[[@LINE-19]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
|
||||
// CHECK:STDERR: fn G[T:! A](t: T) {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
G({} as C);
|
||||
|
||||
// CHECK:STDERR: fail_incomplete_interface.carbon:[[@LINE+7]]:3: error: cannot convert type `C` into type implementing `A & B` [ConversionFailureTypeToFacet]
|
||||
// CHECK:STDERR: H({} as C);
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
// CHECK:STDERR: fail_incomplete_interface.carbon:[[@LINE-27]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
|
||||
// CHECK:STDERR: fn H[T:! A & B](t: T) {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
H({} as C);
|
||||
}
|
||||
|
||||
// --- fail_incomplete_constraint.carbon
|
||||
// --- fail_incomplete_interface_without_forward_decl.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
constraint A;
|
||||
interface B {}
|
||||
interface X;
|
||||
class C {}
|
||||
|
||||
fn G[T:! A](t: T) {}
|
||||
fn H[T:! A & B](t: T) {}
|
||||
// Requires X complete.
|
||||
// CHECK:STDERR: fail_incomplete_interface_without_forward_decl.carbon:[[@LINE+7]]:1: error: definition of impl as incomplete facet type `X` [ImplAsIncompleteFacetTypeDefinition]
|
||||
// CHECK:STDERR: impl C as X {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_incomplete_interface_without_forward_decl.carbon:[[@LINE-7]]:1: note: interface was forward declared here [InterfaceForwardDeclaredHere]
|
||||
// CHECK:STDERR: interface X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
impl C as X {}
|
||||
|
||||
// --- fail_unidentified_constraint.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
constraint X;
|
||||
class C {}
|
||||
|
||||
// Requires X identified.
|
||||
// CHECK:STDERR: fail_unidentified_constraint.carbon:[[@LINE+7]]:1: error: facet type `X` cannot be identified in `impl as` [ImplOfUnidentifiedFacetType]
|
||||
// CHECK:STDERR: impl C as X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_unidentified_constraint.carbon:[[@LINE-7]]:1: note: constraint was forward declared here [NamedConstraintForwardDeclaredHere]
|
||||
// CHECK:STDERR: constraint X;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
impl C as X;
|
||||
|
||||
// --- nested_require_incomplete_interface.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
interface Z;
|
||||
constraint Y {
|
||||
require impls Z;
|
||||
}
|
||||
interface X {
|
||||
require impls Y;
|
||||
}
|
||||
|
||||
class C {}
|
||||
|
||||
// Requires X identified.
|
||||
impl C as X;
|
||||
|
||||
// Requires X complete.
|
||||
impl C as X {}
|
||||
|
||||
// --- fail_incomplete_through_constraint.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
interface Z;
|
||||
constraint Y {
|
||||
extend require impls Z;
|
||||
}
|
||||
|
||||
class C {}
|
||||
|
||||
// Requires Y identified.
|
||||
impl C as Y;
|
||||
|
||||
// Requires Y complete.
|
||||
// CHECK:STDERR: fail_incomplete_through_constraint.carbon:[[@LINE+7]]:1: error: definition of impl as incomplete facet type `Y` [ImplAsIncompleteFacetTypeDefinition]
|
||||
// CHECK:STDERR: impl C as Y {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_incomplete_through_constraint.carbon:[[@LINE-14]]:1: note: interface was forward declared here [InterfaceForwardDeclaredHere]
|
||||
// CHECK:STDERR: interface Z;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
impl C as Y {}
|
||||
|
||||
// --- fail_impl_lookup_incomplete.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
constraint Z;
|
||||
|
||||
fn AsZ(T:! Z) {}
|
||||
|
||||
fn F() {
|
||||
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE+7]]:3: error: facet type `A` is incomplete [ImplLookupInIncompleteFacetType]
|
||||
// CHECK:STDERR: C as A;
|
||||
// CHECK:STDERR: ^~~~~~
|
||||
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE-11]]:1: note: constraint was forward declared here [NamedConstraintForwardDeclaredHere]
|
||||
// CHECK:STDERR: constraint A;
|
||||
// Requires Z identified.
|
||||
// CHECK:STDERR: fail_impl_lookup_incomplete.carbon:[[@LINE+10]]:3: error: facet type `Z` can not be identified [ImplLookupInUnidentifiedFacetType]
|
||||
// CHECK:STDERR: AsZ(());
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_impl_lookup_incomplete.carbon:[[@LINE-9]]:1: note: constraint was forward declared here [NamedConstraintForwardDeclaredHere]
|
||||
// CHECK:STDERR: constraint Z;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_impl_lookup_incomplete.carbon:[[@LINE-10]]:8: note: initializing generic parameter `T` declared here [InitializingGenericParam]
|
||||
// CHECK:STDERR: fn AsZ(T:! Z) {}
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR:
|
||||
C as A;
|
||||
|
||||
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE+7]]:3: error: facet type `B & A` is incomplete [ImplLookupInIncompleteFacetType]
|
||||
// CHECK:STDERR: C as (A & B);
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE-20]]:1: note: constraint was forward declared here [NamedConstraintForwardDeclaredHere]
|
||||
// CHECK:STDERR: constraint A;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
C as (A & B);
|
||||
|
||||
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE+10]]:3: error: facet type `A` is incomplete [ImplLookupInIncompleteFacetType]
|
||||
// CHECK:STDERR: G({} as C);
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE-29]]:1: note: constraint was forward declared here [NamedConstraintForwardDeclaredHere]
|
||||
// CHECK:STDERR: constraint A;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE-28]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
|
||||
// CHECK:STDERR: fn G[T:! A](t: T) {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
G({} as C);
|
||||
|
||||
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE+10]]:3: error: facet type `B & A` is incomplete [ImplLookupInIncompleteFacetType]
|
||||
// CHECK:STDERR: H({} as C);
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE-41]]:1: note: constraint was forward declared here [NamedConstraintForwardDeclaredHere]
|
||||
// CHECK:STDERR: constraint A;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE-39]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere]
|
||||
// CHECK:STDERR: fn H[T:! A & B](t: T) {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
H({} as C);
|
||||
AsZ(());
|
||||
}
|
||||
|
||||
@@ -110,3 +110,16 @@ class C {
|
||||
// CHECK:STDERR:
|
||||
require impls Y;
|
||||
}
|
||||
|
||||
// --- fail_extend_require_type.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
interface Y {}
|
||||
|
||||
interface Z {
|
||||
// CHECK:STDERR: fail_extend_require_type.carbon:[[@LINE+4]]:18: error: `extend require impls` with explicit type [RequireImplsExtendWithExplicitSelf]
|
||||
// CHECK:STDERR: extend require () impls Y;
|
||||
// CHECK:STDERR: ^~
|
||||
// CHECK:STDERR:
|
||||
extend require () impls Y;
|
||||
}
|
||||
|
||||
+88
-47
@@ -10,34 +10,16 @@
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/impl_as_named_constraint.carbon
|
||||
|
||||
// --- fail_incomplete_constraint.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
constraint A;
|
||||
|
||||
class C {}
|
||||
|
||||
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE+7]]:1: error: facet type `A` cannot be identified in `impl as` [ImplOfUnidentifiedFacetType]
|
||||
// CHECK:STDERR: impl C as A {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_incomplete_constraint.carbon:[[@LINE-7]]:1: note: constraint was forward declared here [NamedConstraintForwardDeclaredHere]
|
||||
// CHECK:STDERR: constraint A;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
impl C as A {}
|
||||
|
||||
// --- fail_empty_constraint.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
constraint A {}
|
||||
|
||||
class C {}
|
||||
|
||||
// CHECK:STDERR: fail_empty_constraint.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
|
||||
// CHECK:STDERR: impl C as A {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~
|
||||
// CHECK:STDERR: impl () as A {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
impl C as A {}
|
||||
impl () as A {}
|
||||
|
||||
// --- fail_too_many_interfaces_in_constraint.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
@@ -45,50 +27,109 @@ library "[[@TEST_NAME]]";
|
||||
interface A1;
|
||||
interface A2;
|
||||
constraint B {
|
||||
require impls A1;
|
||||
require impls A2;
|
||||
extend require impls A1;
|
||||
extend require impls A2;
|
||||
}
|
||||
|
||||
class C {}
|
||||
|
||||
// TODO: This should fail since B does not name a single interface, it names
|
||||
// more than one.
|
||||
// CHECK:STDERR: fail_too_many_interfaces_in_constraint.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
|
||||
// CHECK:STDERR: impl C as B {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_too_many_interfaces_in_constraint.carbon:[[@LINE+4]]:1: error: impl as 2 interfaces, expected 1 [ImplOfNotOneInterface]
|
||||
// CHECK:STDERR: impl () as B {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
impl C as B {}
|
||||
impl () as B {}
|
||||
|
||||
// --- fail_todo_one_declared_interface_in_constraint.carbon
|
||||
// --- one_extend_impls_interface_in_constraint.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
// TODO: This should work since B can be identified to have one interface.
|
||||
interface A;
|
||||
constraint B {
|
||||
extend require impls A;
|
||||
}
|
||||
|
||||
// Requries B identified.
|
||||
impl () as B;
|
||||
|
||||
interface A {}
|
||||
|
||||
// Requries B complete.
|
||||
impl () as B {}
|
||||
|
||||
// --- fail_one_impls_interface_in_constraint.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
interface A;
|
||||
constraint B {
|
||||
require impls A;
|
||||
}
|
||||
|
||||
class C {}
|
||||
// CHECK:STDERR: fail_todo_one_declared_interface_in_constraint.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
|
||||
// CHECK:STDERR: impl C as B {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_one_impls_interface_in_constraint.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
|
||||
// CHECK:STDERR: impl () as B {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
impl C as B {}
|
||||
impl () as B {}
|
||||
|
||||
// --- fail_todo_one_defined_interface_in_constraint.carbon
|
||||
// --- nested_constraints.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
// TODO: This should work since B can be identified to have one interface.
|
||||
|
||||
interface A {}
|
||||
constraint B {
|
||||
require impls A;
|
||||
extend require impls A;
|
||||
}
|
||||
constraint C {
|
||||
extend require impls B;
|
||||
}
|
||||
|
||||
class C {}
|
||||
// CHECK:STDERR: fail_todo_one_defined_interface_in_constraint.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
|
||||
// CHECK:STDERR: impl C as B {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~
|
||||
impl () as C {}
|
||||
|
||||
// --- fail_nested_constraints_not_extend_outer.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
interface A {}
|
||||
|
||||
constraint B {
|
||||
extend require impls A;
|
||||
}
|
||||
constraint C {
|
||||
require impls B;
|
||||
}
|
||||
|
||||
// CHECK:STDERR: fail_nested_constraints_not_extend_outer.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
|
||||
// CHECK:STDERR: impl () as C {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
impl C as B {}
|
||||
impl () as C {}
|
||||
|
||||
// --- fail_nested_constraints_not_extend_inner.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
interface A {}
|
||||
|
||||
constraint B {
|
||||
require impls A;
|
||||
}
|
||||
constraint C {
|
||||
extend require impls B;
|
||||
}
|
||||
|
||||
// CHECK:STDERR: fail_nested_constraints_not_extend_inner.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
|
||||
// CHECK:STDERR: impl () as C {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
impl () as C {}
|
||||
|
||||
// --- fail_nested_constraints_not_extend_both.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
interface A {}
|
||||
|
||||
constraint B {
|
||||
require impls A;
|
||||
}
|
||||
constraint C {
|
||||
require impls B;
|
||||
}
|
||||
|
||||
// CHECK:STDERR: fail_nested_constraints_not_extend_both.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
|
||||
// CHECK:STDERR: impl () as C {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
impl () as C {}
|
||||
|
||||
@@ -49,7 +49,7 @@ class C {}
|
||||
// CHECK:STDERR:
|
||||
impl C as A;
|
||||
|
||||
// --- fail_todo_import_complete.carbon
|
||||
// --- import_complete.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import library "b";
|
||||
@@ -57,19 +57,9 @@ import library "b";
|
||||
class C {}
|
||||
|
||||
// This requires that B is identified.
|
||||
// TODO: This should work.
|
||||
// CHECK:STDERR: fail_todo_import_complete.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
|
||||
// CHECK:STDERR: impl C as B;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
impl C as B;
|
||||
|
||||
// This requires that B is complete.
|
||||
// TODO: This should work.
|
||||
// CHECK:STDERR: fail_todo_import_complete.carbon:[[@LINE+4]]:1: error: impl as 0 interfaces, expected 1 [ImplOfNotOneInterface]
|
||||
// CHECK:STDERR: impl C as B {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
impl C as B {}
|
||||
|
||||
// CHECK:STDOUT: --- a.impl.carbon
|
||||
|
||||
+4
-16
@@ -29,14 +29,10 @@ fn F(T:! Z) {
|
||||
// CHECK:STDERR: ^~~~
|
||||
// CHECK:STDERR:
|
||||
T.YY();
|
||||
// CHECK:STDERR: fail_todo_extend.carbon:[[@LINE+4]]:3: error: cannot convert type `T` that implements `Z` into type implementing `Y` [ConversionFailureFacetToFacet]
|
||||
// CHECK:STDERR: T.(Y.YY)();
|
||||
// CHECK:STDERR: ^~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
T.(Y.YY)();
|
||||
}
|
||||
|
||||
// --- fail_todo_implicit_self_impls.carbon
|
||||
// --- implicit_self_impls.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
interface Y {
|
||||
@@ -50,14 +46,10 @@ constraint Z {
|
||||
//@dump-sem-ir-end
|
||||
|
||||
fn F(T:! Z) {
|
||||
// CHECK:STDERR: fail_todo_implicit_self_impls.carbon:[[@LINE+4]]:3: error: cannot convert type `T` that implements `Z` into type implementing `Y` [ConversionFailureFacetToFacet]
|
||||
// CHECK:STDERR: T.(Y.YY)();
|
||||
// CHECK:STDERR: ^~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
T.(Y.YY)();
|
||||
}
|
||||
|
||||
// --- fail_todo_explicit_self_impls.carbon
|
||||
// --- explicit_self_impls.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
interface Y {
|
||||
@@ -71,10 +63,6 @@ constraint Z {
|
||||
//@dump-sem-ir-end
|
||||
|
||||
fn F(T:! Z) {
|
||||
// CHECK:STDERR: fail_todo_explicit_self_impls.carbon:[[@LINE+4]]:3: error: cannot convert type `T` that implements `Z` into type implementing `Y` [ConversionFailureFacetToFacet]
|
||||
// CHECK:STDERR: T.(Y.YY)();
|
||||
// CHECK:STDERR: ^~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
T.(Y.YY)();
|
||||
}
|
||||
|
||||
@@ -342,7 +330,7 @@ constraint Z {
|
||||
// CHECK:STDOUT: %Self.binding.as_type => constants.%Self.binding.as_type
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_implicit_self_impls.carbon
|
||||
// CHECK:STDOUT: --- implicit_self_impls.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %Y.type: type = facet_type <@Y> [concrete]
|
||||
@@ -387,7 +375,7 @@ constraint Z {
|
||||
// CHECK:STDOUT: %Self.binding.as_type => constants.%Self.binding.as_type
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_explicit_self_impls.carbon
|
||||
// CHECK:STDOUT: --- explicit_self_impls.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %Y.type: type = facet_type <@Y> [concrete]
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "toolchain/check/type_completion.h"
|
||||
|
||||
#include "common/concepts.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "toolchain/base/kind_switch.h"
|
||||
#include "toolchain/check/cpp/import.h"
|
||||
@@ -69,6 +70,18 @@ static auto NoteIncompleteNamedConstraint(
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires SameAsOneOf<T, SemIR::Interface, SemIR::NamedConstraint>
|
||||
static auto ForEachRequireImpls(
|
||||
Context& context, const T& entity,
|
||||
llvm::function_ref<auto(const SemIR::RequireImpls&)->void> f) -> void {
|
||||
for (auto require_impls_id :
|
||||
context.require_impls_blocks().Get(entity.require_impls_block_id)) {
|
||||
const auto& require = context.require_impls().Get(require_impls_id);
|
||||
f(require);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Worklist-based type completion mechanism.
|
||||
//
|
||||
@@ -397,15 +410,15 @@ auto TypeCompleter::AddNestedIncompleteTypes(SemIR::Inst type_inst) -> bool {
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::FacetType inst): {
|
||||
// TODO: Get the complete facet type here.
|
||||
auto identified_id =
|
||||
RequireIdentifiedFacetType(*context_, inst, diagnoser_);
|
||||
if (!identified_id.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& identified =
|
||||
context_->identified_facet_types().Get(identified_id);
|
||||
// Every mentioned interface needs to be complete.
|
||||
|
||||
for (auto req_interface : identified.required_interfaces()) {
|
||||
auto interface_id = req_interface.interface_id;
|
||||
const auto& interface = context_->interfaces().Get(interface_id);
|
||||
@@ -771,18 +784,11 @@ auto RequireConcreteType(Context& context, SemIR::TypeId type_id,
|
||||
return true;
|
||||
}
|
||||
|
||||
auto RequireIdentifiedFacetType(Context& context,
|
||||
const SemIR::FacetType& facet_type,
|
||||
MakeDiagnosticBuilderFn diagnoser)
|
||||
-> SemIR::IdentifiedFacetTypeId {
|
||||
if (auto identified_id =
|
||||
context.identified_facet_types().TryGetId(facet_type.facet_type_id);
|
||||
identified_id.has_value()) {
|
||||
return identified_id;
|
||||
}
|
||||
const auto& facet_type_info =
|
||||
context.facet_types().Get(facet_type.facet_type_id);
|
||||
|
||||
// Require all named constraints in the facet type are identified. For a named
|
||||
// constraint, this means the constraint definition is complete.
|
||||
static auto RequireIdentifiedNamedConstraints(
|
||||
Context& context, const SemIR::FacetTypeInfo& facet_type_info,
|
||||
MakeDiagnosticBuilderFn diagnoser) -> bool {
|
||||
auto named_constraint_ids = llvm::map_range(
|
||||
llvm::concat<const SemIR::SpecificNamedConstraint>(
|
||||
facet_type_info.extend_named_constraints,
|
||||
@@ -797,15 +803,84 @@ auto RequireIdentifiedFacetType(Context& context,
|
||||
NoteIncompleteNamedConstraint(context, named_constraint_id, builder);
|
||||
builder.Emit();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
auto RequireIdentifiedFacetType(Context& context,
|
||||
const SemIR::FacetType& facet_type,
|
||||
MakeDiagnosticBuilderFn diagnoser)
|
||||
-> SemIR::IdentifiedFacetTypeId {
|
||||
if (auto identified_id =
|
||||
context.identified_facet_types().TryGetId(facet_type.facet_type_id);
|
||||
identified_id.has_value()) {
|
||||
return identified_id;
|
||||
}
|
||||
|
||||
// Work queue.
|
||||
llvm::SmallVector<SemIR::FacetTypeId> extend_facet_types = {
|
||||
facet_type.facet_type_id};
|
||||
llvm::SmallVector<SemIR::FacetTypeId> impls_facet_types;
|
||||
|
||||
// Outputs for the IdentifiedFacetType.
|
||||
llvm::SmallVector<SemIR::SpecificInterface> extends;
|
||||
llvm::SmallVector<SemIR::SpecificInterface> self_impls;
|
||||
|
||||
while (true) {
|
||||
auto next_facet_type_id = SemIR::FacetTypeId::None;
|
||||
bool facet_type_extends = false;
|
||||
if (!extend_facet_types.empty()) {
|
||||
next_facet_type_id = extend_facet_types.pop_back_val();
|
||||
facet_type_extends = true;
|
||||
} else if (!impls_facet_types.empty()) {
|
||||
next_facet_type_id = impls_facet_types.pop_back_val();
|
||||
facet_type_extends = false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
const auto& facet_type_info = context.facet_types().Get(next_facet_type_id);
|
||||
|
||||
if (!RequireIdentifiedNamedConstraints(context, facet_type_info,
|
||||
diagnoser)) {
|
||||
return SemIR::IdentifiedFacetTypeId::None;
|
||||
}
|
||||
|
||||
if (facet_type_extends) {
|
||||
llvm::append_range(extends, facet_type_info.extend_constraints);
|
||||
} else {
|
||||
llvm::append_range(self_impls, facet_type_info.extend_constraints);
|
||||
}
|
||||
llvm::append_range(self_impls, facet_type_info.self_impls_constraints);
|
||||
|
||||
for (auto extend : facet_type_info.extend_named_constraints) {
|
||||
const auto& constraint =
|
||||
context.named_constraints().Get(extend.named_constraint_id);
|
||||
ForEachRequireImpls(
|
||||
context, constraint, [&](const SemIR::RequireImpls& require) {
|
||||
if (facet_type_extends && require.extend_self) {
|
||||
extend_facet_types.push_back(require.facet_type_id);
|
||||
} else {
|
||||
impls_facet_types.push_back(require.facet_type_id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (auto impls : facet_type_info.self_impls_named_constraints) {
|
||||
const auto& constraint =
|
||||
context.named_constraints().Get(impls.named_constraint_id);
|
||||
ForEachRequireImpls(context, constraint,
|
||||
[&](const SemIR::RequireImpls& require) {
|
||||
impls_facet_types.push_back(require.facet_type_id);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: expand named constraints
|
||||
// TODO: Process other kinds of requirements.
|
||||
return context.identified_facet_types().Add(
|
||||
facet_type.facet_type_id, {facet_type_info.extend_constraints,
|
||||
facet_type_info.self_impls_constraints});
|
||||
return context.identified_facet_types().Add(facet_type.facet_type_id,
|
||||
{extends, self_impls});
|
||||
}
|
||||
|
||||
auto AsCompleteType(Context& context, SemIR::TypeId type_id,
|
||||
|
||||
@@ -360,13 +360,14 @@ CARBON_DIAGNOSTIC_KIND(MissingImplInMemberAccess)
|
||||
CARBON_DIAGNOSTIC_KIND(MissingImplInMemberAccessNote)
|
||||
CARBON_DIAGNOSTIC_KIND(ImplLookupCycle)
|
||||
CARBON_DIAGNOSTIC_KIND(ImplLookupCycleNote)
|
||||
CARBON_DIAGNOSTIC_KIND(ImplLookupInIncompleteFacetType)
|
||||
CARBON_DIAGNOSTIC_KIND(ImplLookupInUnidentifiedFacetType)
|
||||
|
||||
// Require checking.
|
||||
CARBON_DIAGNOSTIC_KIND(RequireImplsExtendWithExplicitSelf)
|
||||
CARBON_DIAGNOSTIC_KIND(RequireImplsMissingFacetType)
|
||||
CARBON_DIAGNOSTIC_KIND(RequireImplsMissingSelf)
|
||||
CARBON_DIAGNOSTIC_KIND(RequireInWrongScope)
|
||||
CARBON_DIAGNOSTIC_KIND(RequireImplsUnidentifiedFacetType)
|
||||
CARBON_DIAGNOSTIC_KIND(RequireInWrongScope)
|
||||
|
||||
// Let declaration checking.
|
||||
CARBON_DIAGNOSTIC_KIND(ExpectedInitializerAfterLet)
|
||||
|
||||
@@ -246,8 +246,10 @@ struct Worklist {
|
||||
auto Add(RequireImplsId require_id) -> void {
|
||||
CARBON_CHECK(require_id.has_value());
|
||||
const auto& require = sem_ir->require_impls().Get(require_id);
|
||||
Add(require.self_id);
|
||||
Add(require.facet_type_id);
|
||||
Add(sem_ir->constant_values().Get(require.self_id));
|
||||
Add(sem_ir->constant_values().Get(require.facet_type_inst_id));
|
||||
contents.push_back(require.extend_self);
|
||||
Add(require.parent_scope_id);
|
||||
}
|
||||
|
||||
auto Add(AssociatedConstantId assoc_const_id) -> void {
|
||||
|
||||
@@ -24,6 +24,8 @@ struct RequireImpls : Printable<RequireImpls> {
|
||||
TypeInstId facet_type_inst_id;
|
||||
// The `FacetTypeInfo` derived from the `facet_type_inst_id` instruction.
|
||||
FacetTypeId facet_type_id;
|
||||
// If the facet type extends `Self`. When true, the `self_id` will be `Self`.
|
||||
bool extend_self;
|
||||
|
||||
// The location of the `require` declaration.
|
||||
InstId decl_id;
|
||||
|
||||
Reference in New Issue
Block a user