mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 09:51:04 +01:00
Use a "type structure" of each impl to choose the best match (#5124)
The type structure is built for the impl lookup query for the
combination of the self type and the interface being queried. Then it is
built for each `impl` definition that is a potential candidate.
The type structures are compared to ensure they have a compatible
structure, and the `impl` declaration is not considered if they do not.
Finally, the type structures are used as a sorting key for the candidate
`impl` declarations, with the most-specified type structures (the ones
with the furthest distance to the first symbolic value) coming first in
the ordering.
See
https://docs.carbon-lang.dev/docs/design/generics/overview.html#parameterized-impl-declarations
for the design of the type structure and related ordering.
Most of the commits in this PR landed in #5158 (11ae0e27ab) by
mistake, but this includes the final changes since that PR was written.
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
co-authored by
Richard Smith
parent
9131b3a0de
commit
6041e9aa9d
@@ -15,10 +15,6 @@ library "[[@TEST_NAME]]";
|
||||
// Check that we get a reasonable diagnostic for an unimplemented operation on a
|
||||
// template dependent expression.
|
||||
fn F[template T:! type](x: T) -> i32 {
|
||||
// CHECK:STDERR: fail_todo_unimplemented_operator.carbon:[[@LINE+8]]:10: error: semantics TODO: `Impl lookup on template-dependent type value` [SemanticsTodo]
|
||||
// CHECK:STDERR: return x.n * 3;
|
||||
// CHECK:STDERR: ^~~
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_todo_unimplemented_operator.carbon:[[@LINE+4]]:10: error: cannot access member of interface `Core.Mul` in type `<dependent type>` that does not implement that interface [MissingImplInMemberAccess]
|
||||
// CHECK:STDERR: return x.n * 3;
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
@@ -38,10 +34,6 @@ class C {
|
||||
// template dependent value where the type is concrete but determined through
|
||||
// the template dependent value.
|
||||
fn F(template c:! C) -> i32 {
|
||||
// CHECK:STDERR: fail_todo_unimplemented_value.carbon:[[@LINE+8]]:10: error: semantics TODO: `Impl lookup on template-dependent type value` [SemanticsTodo]
|
||||
// CHECK:STDERR: return c.n * 3;
|
||||
// CHECK:STDERR: ^~~
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_todo_unimplemented_value.carbon:[[@LINE+4]]:10: error: cannot access member of interface `Core.Mul` in type `<dependent type>` that does not implement that interface [MissingImplInMemberAccess]
|
||||
// CHECK:STDERR: return c.n * 3;
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
@@ -126,15 +118,15 @@ fn F[template T:! type](x: T) {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !definition:
|
||||
// CHECK:STDOUT: %require_complete: <witness> = require_complete_type @F.%T.loc6_15.2 (%T) [template = %require_complete (constants.%require_complete.4ae)]
|
||||
// CHECK:STDOUT: %.loc15_11.3: <instruction> = refine_type_action %x.ref, @F.%T.loc6_15.2 (%T) [template]
|
||||
// CHECK:STDOUT: %.loc15_11.4: <instruction> = access_member_action %.loc15_11.1, n [template]
|
||||
// CHECK:STDOUT: %.loc15_11.5: type = type_of_inst %.loc15_11.4 [template]
|
||||
// CHECK:STDOUT: %.loc11_11.3: <instruction> = refine_type_action %x.ref, @F.%T.loc6_15.2 (%T) [template]
|
||||
// CHECK:STDOUT: %.loc11_11.4: <instruction> = access_member_action %.loc11_11.1, n [template]
|
||||
// CHECK:STDOUT: %.loc11_11.5: type = type_of_inst %.loc11_11.4 [template]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn[%T.patt.loc6_15.1: type](%x.param_patt: @F.%T.loc6_15.2 (%T)) -> %i32 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %x.ref: @F.%T.loc6_15.2 (%T) = name_ref x, %x
|
||||
// CHECK:STDOUT: %.loc15_11.1: @F.%T.loc6_15.2 (%T) = splice_inst %.loc15_11.3
|
||||
// CHECK:STDOUT: %.loc15_11.2: @F.%.loc15_11.5 (@F.%.loc15_11.5) = splice_inst %.loc15_11.4
|
||||
// CHECK:STDOUT: %.loc11_11.1: @F.%T.loc6_15.2 (%T) = splice_inst %.loc11_11.3
|
||||
// CHECK:STDOUT: %.loc11_11.2: @F.%.loc11_11.5 (@F.%.loc11_11.5) = splice_inst %.loc11_11.4
|
||||
// CHECK:STDOUT: %int_3: Core.IntLiteral = int_value 3 [concrete = constants.%int_3]
|
||||
// CHECK:STDOUT: return <error>
|
||||
// CHECK:STDOUT: }
|
||||
@@ -211,13 +203,13 @@ fn F[template T:! type](x: T) {
|
||||
// CHECK:STDOUT: %c.patt.loc11_15.2: %C = symbolic_binding_pattern c, 0, template [template = %c.patt.loc11_15.2 (constants.%c.patt)]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !definition:
|
||||
// CHECK:STDOUT: %.loc20_11.2: <instruction> = access_member_action %c.ref, n [template]
|
||||
// CHECK:STDOUT: %.loc20_11.3: type = type_of_inst %.loc20_11.2 [template]
|
||||
// CHECK:STDOUT: %.loc16_11.2: <instruction> = access_member_action %c.ref, n [template]
|
||||
// CHECK:STDOUT: %.loc16_11.3: type = type_of_inst %.loc16_11.2 [template]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn(%c.patt.loc11_15.1: %C) -> %i32 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %c.ref: %C = name_ref c, %c.loc11_15.1 [template = %c.loc11_15.2 (constants.%c)]
|
||||
// CHECK:STDOUT: %.loc20_11.1: @F.%.loc20_11.3 (@F.%.loc20_11.3) = splice_inst %.loc20_11.2
|
||||
// CHECK:STDOUT: %.loc16_11.1: @F.%.loc16_11.3 (@F.%.loc16_11.3) = splice_inst %.loc16_11.2
|
||||
// CHECK:STDOUT: %int_3: Core.IntLiteral = int_value 3 [concrete = constants.%int_3]
|
||||
// CHECK:STDOUT: return <error>
|
||||
// CHECK:STDOUT: }
|
||||
|
||||
@@ -185,6 +185,15 @@ class TypeStructureBuilder {
|
||||
Push(SymbolicType());
|
||||
break;
|
||||
}
|
||||
case SemIR::TypeOfInst::Kind: {
|
||||
// TODO: For a template value with a fixed type, such as `template n:!
|
||||
// i32`, we could look at the type of the value to see if it's
|
||||
// template-dependent (which it's not here) and add that type to the
|
||||
// type structure?
|
||||
// https://github.com/carbon-language/carbon-lang/pull/5124#discussion_r2006617038
|
||||
Push(SymbolicType());
|
||||
break;
|
||||
}
|
||||
|
||||
// ==== Concrete types ====
|
||||
|
||||
@@ -287,36 +296,6 @@ class TypeStructureBuilder {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::TypeOfInst type_of): {
|
||||
(void)type_of;
|
||||
auto const_id = context_.constant_values().Get(inst_id);
|
||||
// TODO: TypeOfInst should not be encountered in impl lookup with a
|
||||
// template-dependent value, since impl lookup on such values should
|
||||
// be deferred to type-checking the specific. So this should become a
|
||||
// CARBON_FATAL code path. For now it is possible, though, to reach
|
||||
// here and it results in a diagnostic.
|
||||
//
|
||||
// However, TypeOfInst can be determined to be a concrete value for a
|
||||
// template value with a non-template dependent type. This currently
|
||||
// does not happen though, the TypeOfInst is always template
|
||||
// dependent. If it does in the future then we will want to use the
|
||||
// concrete constant value instruction of `inst_id` in the type
|
||||
// structure:
|
||||
// if (const_id.is_concrete()) {
|
||||
// PushInstId(context_.constant_values().GetInstId(const_id));
|
||||
// }
|
||||
//
|
||||
// If TypeOfInst was used for more general metaprogramming then we may
|
||||
// need to handle both concrete and perhaps symbolic (non-template)
|
||||
// values of TypeOfInst.
|
||||
CARBON_CHECK(const_id.is_symbolic());
|
||||
auto sym = context_.constant_values().GetSymbolicConstant(const_id);
|
||||
CARBON_CHECK(sym.dependence == SemIR::ConstantDependence::Template,
|
||||
"TypeOfInst with non-template symbolic value?");
|
||||
context_.TODO(context_.insts().GetLocId(inst_id),
|
||||
"Impl lookup on template-dependent type value");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
CARBON_FATAL("Unhandled type instruction {0}", inst_id);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user