diff --git a/core/prelude/operators/bitwise.carbon b/core/prelude/operators/bitwise.carbon index 1eecda4b94b0..e20ddff73e50 100644 --- a/core/prelude/operators/bitwise.carbon +++ b/core/prelude/operators/bitwise.carbon @@ -87,3 +87,11 @@ impl IntLiteral() as LeftShift { impl IntLiteral() as RightShift { fn Op[self: Self](other: Self) -> Self = "int.right_shift"; } + +// Operations for `type`. These need to be here because `type` has no +// associated library of its own. + +// Facet type combination. +impl forall [T:! type] T as BitAnd { + fn Op[self: Self](other: Self) -> Self = "type.and"; +} diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index 29ac9e51c8fc..c5cb700e864b 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -331,6 +331,18 @@ static auto MakeFloatResult(Context& context, SemIR::TypeId type_id, Phase::Concrete); } +// Creates a FacetType constant. +static auto MakeFacetTypeResult(Context& context, + const SemIR::FacetTypeInfo& info, Phase phase) + -> SemIR::ConstantId { + SemIR::FacetTypeId facet_type_id = context.facet_types().Add(info); + return MakeConstantResult( + context, + SemIR::FacetType{.type_id = SemIR::TypeType::SingletonTypeId, + .facet_type_id = facet_type_id}, + phase); +} + // `GetConstantValue` checks to see whether the provided ID describes a value // with constant phase, and if so, returns the corresponding constant value. // Overloads are provided for different kinds of ID. @@ -1289,11 +1301,12 @@ static auto PerformBuiltinBoolComparison( } // Returns a constant for a call to a builtin function. -static auto MakeConstantForBuiltinCall(Context& context, SemIRLoc loc, +static auto MakeConstantForBuiltinCall(EvalContext& eval_context, SemIRLoc loc, SemIR::Call call, SemIR::BuiltinFunctionKind builtin_kind, llvm::ArrayRef arg_ids, Phase phase) -> SemIR::ConstantId { + auto& context = eval_context.context(); switch (builtin_kind) { case SemIR::BuiltinFunctionKind::None: CARBON_FATAL("Not a builtin function."); @@ -1306,6 +1319,46 @@ static auto MakeConstantForBuiltinCall(Context& context, SemIRLoc loc, return SemIR::ConstantId::NotConstant; } + case SemIR::BuiltinFunctionKind::TypeAnd: { + CARBON_CHECK(arg_ids.size() == 2); + auto lhs_facet_type_id = SemIR::FacetTypeId::None; + auto rhs_facet_type_id = SemIR::FacetTypeId::None; + for (auto [facet_type_id, arg_id] : + llvm::zip(std::to_array({&lhs_facet_type_id, &rhs_facet_type_id}), + arg_ids)) { + if (auto facet_type = + context.insts().TryGetAs(arg_id)) { + *facet_type_id = facet_type->facet_type_id; + } else { + CARBON_DIAGNOSTIC(FacetTypeRequiredForTypeAndOperator, Error, + "non-facet type {0} combined with `&` operator", + SemIR::TypeId); + // TODO: Find a location for the lhs or rhs specifically, instead of + // the whole thing. If that's not possible we can change the text to + // say if it's referring to the left or the right side for the error. + // The `arg_id` instruction has no location in it for some reason. + context.emitter().Emit( + loc, FacetTypeRequiredForTypeAndOperator, + context.types().GetTypeIdForTypeInstId(arg_id)); + } + } + // Allow errors to be diagnosed for both sides of the operator before + // returning here if any error occurred on either side. + if (!lhs_facet_type_id.has_value() || !rhs_facet_type_id.has_value()) { + return SemIR::ErrorInst::SingletonConstantId; + } + // Reuse one of the argument instructions if nothing has changed. + if (lhs_facet_type_id == rhs_facet_type_id) { + return context.types().GetConstantId( + context.types().GetTypeIdForTypeInstId(arg_ids[0])); + } + auto info = SemIR::FacetTypeInfo::Combine( + context.facet_types().Get(lhs_facet_type_id), + context.facet_types().Get(rhs_facet_type_id)); + info.Canonicalize(); + return MakeFacetTypeResult(eval_context.context(), info, phase); + } + case SemIR::BuiltinFunctionKind::IntLiteralMakeType: { return context.constant_values().Get( SemIR::IntLiteralType::SingletonInstId); @@ -1525,25 +1578,13 @@ static auto MakeConstantForCall(EvalContext& eval_context, SemIRLoc loc, // Handle calls to builtins. if (builtin_kind != SemIR::BuiltinFunctionKind::None) { return MakeConstantForBuiltinCall( - eval_context.context(), loc, call, builtin_kind, + eval_context, loc, call, builtin_kind, eval_context.inst_blocks().Get(call.args_id), phase); } return SemIR::ConstantId::NotConstant; } -// Creates a FacetType constant. -static auto MakeFacetTypeResult(Context& context, - const SemIR::FacetTypeInfo& info, Phase phase) - -> SemIR::ConstantId { - SemIR::FacetTypeId facet_type_id = context.facet_types().Add(info); - return MakeConstantResult( - context, - SemIR::FacetType{.type_id = SemIR::TypeType::SingletonTypeId, - .facet_type_id = facet_type_id}, - phase); -} - // The result of constant evaluation of an instruction. class ConstantEvalResult { public: diff --git a/toolchain/check/testdata/builtin_conversions/value_with_type_through_access.carbon b/toolchain/check/testdata/builtin_conversions/value_with_type_through_access.carbon index 864e59931512..bb9b699d19a1 100644 --- a/toolchain/check/testdata/builtin_conversions/value_with_type_through_access.carbon +++ b/toolchain/check/testdata/builtin_conversions/value_with_type_through_access.carbon @@ -658,11 +658,11 @@ fn G() { // CHECK:STDOUT: constants { // CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete] // CHECK:STDOUT: %array_type: type = array_type %int_1, type [concrete] -// CHECK:STDOUT: %T: %array_type = bind_symbolic_name T, 0 [symbolic] -// CHECK:STDOUT: %T.patt: %array_type = symbolic_binding_pattern T, 0 [symbolic] +// CHECK:STDOUT: %T.eb6: %array_type = bind_symbolic_name T, 0 [symbolic] +// CHECK:STDOUT: %T.patt.226: %array_type = symbolic_binding_pattern T, 0 [symbolic] // CHECK:STDOUT: %HoldsType.type: type = generic_class_type @HoldsType [concrete] // CHECK:STDOUT: %HoldsType.generic: %HoldsType.type = struct_value () [concrete] -// CHECK:STDOUT: %HoldsType: type = class_type @HoldsType, @HoldsType(%T) [symbolic] +// CHECK:STDOUT: %HoldsType: type = class_type @HoldsType, @HoldsType(%T.eb6) [symbolic] // CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %complete_type.357: = complete_type_witness %empty_struct_type [concrete] // CHECK:STDOUT: %int_0.5c6: Core.IntLiteral = int_value 0 [concrete] @@ -707,19 +707,19 @@ fn G() { // CHECK:STDOUT: } // CHECK:STDOUT: %Core.import = import Core // CHECK:STDOUT: %HoldsType.decl: %HoldsType.type = class_decl @HoldsType [concrete = constants.%HoldsType.generic] { -// CHECK:STDOUT: %T.patt.loc4_17.1: %array_type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc4_17.2 (constants.%T.patt)] -// CHECK:STDOUT: %T.param_patt: %array_type = value_param_pattern %T.patt.loc4_17.1, runtime_param [symbolic = %T.patt.loc4_17.2 (constants.%T.patt)] +// CHECK:STDOUT: %T.patt.loc4_17.1: %array_type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc4_17.2 (constants.%T.patt.226)] +// CHECK:STDOUT: %T.param_patt: %array_type = value_param_pattern %T.patt.loc4_17.1, runtime_param [symbolic = %T.patt.loc4_17.2 (constants.%T.patt.226)] // CHECK:STDOUT: } { // CHECK:STDOUT: %T.param: %array_type = value_param runtime_param // CHECK:STDOUT: %.loc4: type = splice_block %array_type [concrete = constants.%array_type] { // CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1] // CHECK:STDOUT: %array_type: type = array_type %int_1, type [concrete = constants.%array_type] // CHECK:STDOUT: } -// CHECK:STDOUT: %T.loc4_17.1: %array_type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc4_17.2 (constants.%T)] +// CHECK:STDOUT: %T.loc4_17.1: %array_type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc4_17.2 (constants.%T.eb6)] // CHECK:STDOUT: } // CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] { -// CHECK:STDOUT: %T.patt.loc12_6.1: %array_type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc12_6.2 (constants.%T.patt)] -// CHECK:STDOUT: %T.param_patt: %array_type = value_param_pattern %T.patt.loc12_6.1, runtime_param [symbolic = %T.patt.loc12_6.2 (constants.%T.patt)] +// CHECK:STDOUT: %T.patt.loc12_6.1: %array_type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc12_6.2 (constants.%T.patt.226)] +// CHECK:STDOUT: %T.param_patt: %array_type = value_param_pattern %T.patt.loc12_6.1, runtime_param [symbolic = %T.patt.loc12_6.2 (constants.%T.patt.226)] // CHECK:STDOUT: %x.patt: @F.%HoldsType.loc12_40.2 (%HoldsType) = binding_pattern x // CHECK:STDOUT: %x.param_patt: @F.%HoldsType.loc12_40.2 (%HoldsType) = value_param_pattern %x.patt, runtime_param0 // CHECK:STDOUT: %a.patt: = binding_pattern a @@ -730,17 +730,17 @@ fn G() { // CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1] // CHECK:STDOUT: %array_type: type = array_type %int_1, type [concrete = constants.%array_type] // CHECK:STDOUT: } -// CHECK:STDOUT: %T.loc12_6.1: %array_type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc12_6.2 (constants.%T)] +// CHECK:STDOUT: %T.loc12_6.1: %array_type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc12_6.2 (constants.%T.eb6)] // CHECK:STDOUT: %x.param: @F.%HoldsType.loc12_40.2 (%HoldsType) = value_param runtime_param0 // CHECK:STDOUT: %.loc12_40: type = splice_block %HoldsType.loc12_40.1 [symbolic = %HoldsType.loc12_40.2 (constants.%HoldsType)] { // CHECK:STDOUT: %HoldsType.ref: %HoldsType.type = name_ref HoldsType, file.%HoldsType.decl [concrete = constants.%HoldsType.generic] -// CHECK:STDOUT: %T.ref.loc12_39: %array_type = name_ref T, %T.loc12_6.1 [symbolic = %T.loc12_6.2 (constants.%T)] -// CHECK:STDOUT: %HoldsType.loc12_40.1: type = class_type @HoldsType, @HoldsType(constants.%T) [symbolic = %HoldsType.loc12_40.2 (constants.%HoldsType)] +// CHECK:STDOUT: %T.ref.loc12_39: %array_type = name_ref T, %T.loc12_6.1 [symbolic = %T.loc12_6.2 (constants.%T.eb6)] +// CHECK:STDOUT: %HoldsType.loc12_40.1: type = class_type @HoldsType, @HoldsType(constants.%T.eb6) [symbolic = %HoldsType.loc12_40.2 (constants.%HoldsType)] // CHECK:STDOUT: } // CHECK:STDOUT: %x: @F.%HoldsType.loc12_40.2 (%HoldsType) = bind_name x, %x.param // CHECK:STDOUT: %a.param: = value_param runtime_param1 // CHECK:STDOUT: %.1: = splice_block [concrete = ] { -// CHECK:STDOUT: %T.ref.loc12_46: %array_type = name_ref T, %T.loc12_6.1 [symbolic = %T.loc12_6.2 (constants.%T)] +// CHECK:STDOUT: %T.ref.loc12_46: %array_type = name_ref T, %T.loc12_6.1 [symbolic = %T.loc12_6.2 (constants.%T.eb6)] // CHECK:STDOUT: %int_0: Core.IntLiteral = int_value 0 [concrete = constants.%int_0.5c6] // CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] // CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] @@ -761,8 +761,8 @@ fn G() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic class @HoldsType(%T.loc4_17.1: %array_type) { -// CHECK:STDOUT: %T.loc4_17.2: %array_type = bind_symbolic_name T, 0 [symbolic = %T.loc4_17.2 (constants.%T)] -// CHECK:STDOUT: %T.patt.loc4_17.2: %array_type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc4_17.2 (constants.%T.patt)] +// CHECK:STDOUT: %T.loc4_17.2: %array_type = bind_symbolic_name T, 0 [symbolic = %T.loc4_17.2 (constants.%T.eb6)] +// CHECK:STDOUT: %T.patt.loc4_17.2: %array_type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc4_17.2 (constants.%T.patt.226)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: @@ -784,8 +784,8 @@ fn G() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @F(%T.loc12_6.1: %array_type) { -// CHECK:STDOUT: %T.loc12_6.2: %array_type = bind_symbolic_name T, 0 [symbolic = %T.loc12_6.2 (constants.%T)] -// CHECK:STDOUT: %T.patt.loc12_6.2: %array_type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc12_6.2 (constants.%T.patt)] +// CHECK:STDOUT: %T.loc12_6.2: %array_type = bind_symbolic_name T, 0 [symbolic = %T.loc12_6.2 (constants.%T.eb6)] +// CHECK:STDOUT: %T.patt.loc12_6.2: %array_type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc12_6.2 (constants.%T.patt.226)] // CHECK:STDOUT: %HoldsType.loc12_40.2: type = class_type @HoldsType, @HoldsType(%T.loc12_6.2) [symbolic = %HoldsType.loc12_40.2 (constants.%HoldsType)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: @@ -818,16 +818,16 @@ fn G() { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @HoldsType(constants.%T) { -// CHECK:STDOUT: %T.loc4_17.2 => constants.%T -// CHECK:STDOUT: %T.patt.loc4_17.2 => constants.%T +// CHECK:STDOUT: specific @HoldsType(constants.%T.eb6) { +// CHECK:STDOUT: %T.loc4_17.2 => constants.%T.eb6 +// CHECK:STDOUT: %T.patt.loc4_17.2 => constants.%T.eb6 // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @F(constants.%T) { -// CHECK:STDOUT: %T.loc12_6.2 => constants.%T -// CHECK:STDOUT: %T.patt.loc12_6.2 => constants.%T +// CHECK:STDOUT: specific @F(constants.%T.eb6) { +// CHECK:STDOUT: %T.loc12_6.2 => constants.%T.eb6 +// CHECK:STDOUT: %T.patt.loc12_6.2 => constants.%T.eb6 // CHECK:STDOUT: %HoldsType.loc12_40.2 => constants.%HoldsType // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/class/generic/import.carbon b/toolchain/check/testdata/class/generic/import.carbon index 48371f3249f5..749a950ab995 100644 --- a/toolchain/check/testdata/class/generic/import.carbon +++ b/toolchain/check/testdata/class/generic/import.carbon @@ -254,10 +254,10 @@ class Class(U:! type) { // CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] // CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] // CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 [symbolic] +// CHECK:STDOUT: %require_complete.4ae: = require_complete_type %T [symbolic] // CHECK:STDOUT: %Class.type: type = generic_class_type @Class [concrete] // CHECK:STDOUT: %Class.generic: %Class.type = struct_value () [concrete] // CHECK:STDOUT: %Class: type = class_type @Class, @Class(%T) [symbolic] -// CHECK:STDOUT: %require_complete.4ae: = require_complete_type %T [symbolic] // CHECK:STDOUT: %Class.elem: type = unbound_element_type %Class, %T [symbolic] // CHECK:STDOUT: %struct_type.x: type = struct_type {.x: %T} [symbolic] // CHECK:STDOUT: %complete_type.433: = complete_type_witness %struct_type.x [symbolic] @@ -778,12 +778,12 @@ class Class(U:! type) { // CHECK:STDOUT: --- fail_foo.impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] +// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 [symbolic] // CHECK:STDOUT: %U: type = bind_symbolic_name U, 0 [symbolic] // CHECK:STDOUT: %U.patt: type = symbolic_binding_pattern U, 0 [symbolic] // CHECK:STDOUT: %Class.type: type = generic_class_type @Class [concrete] // CHECK:STDOUT: %Class.generic: %Class.type = struct_value () [concrete] -// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] -// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 [symbolic] // CHECK:STDOUT: %.type: type = generic_class_type @.1 [concrete] // CHECK:STDOUT: %.generic: %.type = struct_value () [concrete] // CHECK:STDOUT: %.e41: type = class_type @.1, @.1(%U) [symbolic] diff --git a/toolchain/check/testdata/class/import.carbon b/toolchain/check/testdata/class/import.carbon index 86673494ea2b..9c12f6dda2d7 100644 --- a/toolchain/check/testdata/class/import.carbon +++ b/toolchain/check/testdata/class/import.carbon @@ -361,5 +361,5 @@ fn Run() { // CHECK:STDOUT: // CHECK:STDOUT: fn @F[%self.param_patt: %ForwardDeclared.7b34f2.1]() [from "a.carbon"]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @G[addr .inst1150: %ptr.6cf]() [from "a.carbon"]; +// CHECK:STDOUT: fn @G[addr .inst1179: %ptr.6cf]() [from "a.carbon"]; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/facet/no_prelude/combine.carbon b/toolchain/check/testdata/facet/no_prelude/combine.carbon new file mode 100644 index 000000000000..0f1e76954826 --- /dev/null +++ b/toolchain/check/testdata/facet/no_prelude/combine.carbon @@ -0,0 +1,126 @@ +// 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 +// +// EXTRA-ARGS: --no-dump-sem-ir +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/facet/no_prelude/combine.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/facet/no_prelude/combine.carbon + +// --- core.carbon +package Core; + +interface As(Dest:! type) { + fn Convert[self: Self]() -> Dest; +} + +interface BitAnd { + fn Op[self: Self](other: Self) -> Self; +} + +impl forall [T:! type] T as BitAnd { + fn Op[self: Self](other: Self) -> Self = "type.and"; +} + +// --- fail_combine_with_non_facet_type.carbon +library "[[@TEST_NAME]]"; + +import Core; + +interface A {} +class C {} + +fn F() { + // CHECK:STDERR: fail_combine_with_non_facet_type.carbon:[[@LINE+4]]:23: error: non-facet type `C` combined with `&` operator [FacetTypeRequiredForTypeAndOperator] + // CHECK:STDERR: ({} as C) as (C as (A & C)); + // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: + ({} as C) as (C as (A & C)); + // CHECK:STDERR: fail_combine_with_non_facet_type.carbon:[[@LINE+4]]:23: error: non-facet type `C` combined with `&` operator [FacetTypeRequiredForTypeAndOperator] + // CHECK:STDERR: ({} as C) as (C as (C & A)); + // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: + ({} as C) as (C as (C & A)); + // CHECK:STDERR: fail_combine_with_non_facet_type.carbon:[[@LINE+8]]:23: error: non-facet type `C` combined with `&` operator [FacetTypeRequiredForTypeAndOperator] + // CHECK:STDERR: ({} as C) as (C as (C & C)); + // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_combine_with_non_facet_type.carbon:[[@LINE+4]]:23: error: non-facet type `C` combined with `&` operator [FacetTypeRequiredForTypeAndOperator] + // CHECK:STDERR: ({} as C) as (C as (C & C)); + // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: + ({} as C) as (C as (C & C)); +} + +// --- same.carbon +library "[[@TEST_NAME]]"; + +import Core; + +interface A { + fn G(); +} + +class C {} +impl C as A { + fn G() {} +} + +fn F() { + ({} as C).((A & A).G)(); + (({} as C) as (C as (A & A))).((A & A).G)(); + (({} as C) as (C as (A & A))).(A.G)(); +} + +// --- fail_todo_combine.carbon +library "[[@TEST_NAME]]"; + +import Core; + +interface A {} +interface B { + fn G(); +} + +class C {} +impl C as A {} +impl C as B { + fn G() {} +} + +fn F() { + // CHECK:STDERR: fail_todo_combine.carbon:[[@LINE+4]]:14: error: semantics TODO: `FacetType with more than one required interface. Sort and deduplicate` [SemanticsTodo] + // CHECK:STDERR: ({} as C).((A & B).G)(); + // CHECK:STDERR: ^~~~~~~~~ + // CHECK:STDERR: + ({} as C).((A & B).G)(); + + // CHECK:STDERR: fail_todo_combine.carbon:[[@LINE+11]]:18: error: semantics TODO: `impl lookup for a FacetType with more than one interface` [SemanticsTodo] + // CHECK:STDERR: (({} as C) as (C as (A & B))).((A & B).G)(); + // CHECK:STDERR: ^~~~~~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_todo_combine.carbon:[[@LINE+7]]:18: error: cannot convert from `type` to `A & B` with `as` [ExplicitAsConversionFailure] + // CHECK:STDERR: (({} as C) as (C as (A & B))).((A & B).G)(); + // CHECK:STDERR: ^~~~~~~~~~~~ + // CHECK:STDERR: fail_todo_combine.carbon:[[@LINE+4]]:18: note: type `type` does not implement interface `Core.As(A & B)` [MissingImplInMemberAccessNote] + // CHECK:STDERR: (({} as C) as (C as (A & B))).((A & B).G)(); + // CHECK:STDERR: ^~~~~~~~~~~~ + // CHECK:STDERR: + (({} as C) as (C as (A & B))).((A & B).G)(); + + // CHECK:STDERR: fail_todo_combine.carbon:[[@LINE+11]]:18: error: semantics TODO: `impl lookup for a FacetType with more than one interface` [SemanticsTodo] + // CHECK:STDERR: (({} as C) as (C as (A & B))).((B).G)(); + // CHECK:STDERR: ^~~~~~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_todo_combine.carbon:[[@LINE+7]]:18: error: cannot convert from `type` to `A & B` with `as` [ExplicitAsConversionFailure] + // CHECK:STDERR: (({} as C) as (C as (A & B))).((B).G)(); + // CHECK:STDERR: ^~~~~~~~~~~~ + // CHECK:STDERR: fail_todo_combine.carbon:[[@LINE+4]]:18: note: type `type` does not implement interface `Core.As(A & B)` [MissingImplInMemberAccessNote] + // CHECK:STDERR: (({} as C) as (C as (A & B))).((B).G)(); + // CHECK:STDERR: ^~~~~~~~~~~~ + // CHECK:STDERR: + (({} as C) as (C as (A & B))).((B).G)(); +} diff --git a/toolchain/check/testdata/function/generic/undefined.carbon b/toolchain/check/testdata/function/generic/undefined.carbon index 224ebcb007a5..3487f0afea06 100644 --- a/toolchain/check/testdata/function/generic/undefined.carbon +++ b/toolchain/check/testdata/function/generic/undefined.carbon @@ -185,6 +185,7 @@ fn CallUndefined() -> i32 { // CHECK:STDOUT: %int_0.5c6: Core.IntLiteral = int_value 0 [concrete] // CHECK:STDOUT: %As.type.fd4: type = facet_type <@As, @As(%i32)> [concrete] // CHECK:STDOUT: %Convert.type.99b: type = fn_type @Convert.1, @As(%i32) [concrete] +// CHECK:STDOUT: %require_complete.4ae: = require_complete_type %T [symbolic] // CHECK:STDOUT: %impl_witness.882: = impl_witness (imports.%Core.import_ref.78a), @impl.686(%int_32) [concrete] // CHECK:STDOUT: %Convert.type.4fd: type = fn_type @Convert.5, @impl.686(%int_32) [concrete] // CHECK:STDOUT: %Convert.197: %Convert.type.4fd = struct_value () [concrete] @@ -194,7 +195,6 @@ fn CallUndefined() -> i32 { // CHECK:STDOUT: %Convert.specific_fn: = specific_function %Convert.bound, @Convert.5(%int_32) [concrete] // CHECK:STDOUT: %int_0.6a9: %i32 = int_value 0 [concrete] // CHECK:STDOUT: %Defined.specific_fn: = specific_function %Defined, @Defined(%i32) [concrete] -// CHECK:STDOUT: %require_complete.4ae: = require_complete_type %T [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { diff --git a/toolchain/check/testdata/if_expr/fail_not_in_function.carbon b/toolchain/check/testdata/if_expr/fail_not_in_function.carbon index 168249a779cc..58964c23764c 100644 --- a/toolchain/check/testdata/if_expr/fail_not_in_function.carbon +++ b/toolchain/check/testdata/if_expr/fail_not_in_function.carbon @@ -94,7 +94,7 @@ class C { // CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] // CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] // CHECK:STDOUT: } -// CHECK:STDOUT: %x: %i32 = bind_name x, .inst1072.loc27_14 +// CHECK:STDOUT: %x: %i32 = bind_name x, .inst1101.loc27_14 // CHECK:STDOUT: name_binding_decl { // CHECK:STDOUT: %y.patt: %i32 = binding_pattern y // CHECK:STDOUT: %.loc37: %i32 = var_pattern %y.patt diff --git a/toolchain/check/testdata/index/fail_negative_indexing.carbon b/toolchain/check/testdata/index/fail_negative_indexing.carbon index 9314c80a8c80..11f4a7deba11 100644 --- a/toolchain/check/testdata/index/fail_negative_indexing.carbon +++ b/toolchain/check/testdata/index/fail_negative_indexing.carbon @@ -41,10 +41,10 @@ var d: i32 = c[-10]; // CHECK:STDOUT: %array: %array_type = tuple_value (%int_42.c68, %int_42.c68) [concrete] // CHECK:STDOUT: %int_10: Core.IntLiteral = int_value 10 [concrete] // CHECK:STDOUT: %impl_witness.0f6: = impl_witness (imports.%Core.import_ref.c15) [concrete] -// CHECK:STDOUT: %Op.type.e42: type = fn_type @Op.13 [concrete] +// CHECK:STDOUT: %Op.type.e42: type = fn_type @Op.14 [concrete] // CHECK:STDOUT: %Negate.facet: %Negate.type = facet_value Core.IntLiteral, %impl_witness.0f6 [concrete] // CHECK:STDOUT: %.45d: type = fn_type_with_self_type %Op.type.e42, %Negate.facet [concrete] -// CHECK:STDOUT: %Op.type.1be: type = fn_type @Op.14 [concrete] +// CHECK:STDOUT: %Op.type.1be: type = fn_type @Op.15 [concrete] // CHECK:STDOUT: %Op.bba: %Op.type.1be = struct_value () [concrete] // CHECK:STDOUT: %Op.bound: = bound_method %int_10, %Op.bba [concrete] // CHECK:STDOUT: %int_-10.06d: Core.IntLiteral = int_value -10 [concrete] diff --git a/toolchain/check/testdata/operators/overloaded/bit_complement.carbon b/toolchain/check/testdata/operators/overloaded/bit_complement.carbon index 2c9957e9fe82..941b0250f3f3 100644 --- a/toolchain/check/testdata/operators/overloaded/bit_complement.carbon +++ b/toolchain/check/testdata/operators/overloaded/bit_complement.carbon @@ -32,10 +32,10 @@ fn TestOp(a: C) -> C { // CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete] // CHECK:STDOUT: %BitComplement.type: type = facet_type <@BitComplement> [concrete] // CHECK:STDOUT: %Op.type.f25: type = fn_type @Op.1 [concrete] -// CHECK:STDOUT: %impl_witness: = impl_witness (@impl.5a3.%Op.decl) [concrete] +// CHECK:STDOUT: %impl_witness.40c: = impl_witness (@impl.5a3.%Op.decl) [concrete] // CHECK:STDOUT: %Op.type.544: type = fn_type @Op.2 [concrete] // CHECK:STDOUT: %Op.bf2: %Op.type.544 = struct_value () [concrete] -// CHECK:STDOUT: %BitComplement.facet: %BitComplement.type = facet_value %C, %impl_witness [concrete] +// CHECK:STDOUT: %BitComplement.facet: %BitComplement.type = facet_value %C, %impl_witness.40c [concrete] // CHECK:STDOUT: %C.val: %C = struct_value () [concrete] // CHECK:STDOUT: %TestOp.type: type = fn_type @TestOp [concrete] // CHECK:STDOUT: %TestOp: %TestOp.type = struct_value () [concrete] @@ -64,7 +64,7 @@ fn TestOp(a: C) -> C { // CHECK:STDOUT: %Core.ref: = name_ref Core, imports.%Core [concrete = imports.%Core] // CHECK:STDOUT: %BitComplement.ref: type = name_ref BitComplement, imports.%Core.BitComplement [concrete = constants.%BitComplement.type] // CHECK:STDOUT: } -// CHECK:STDOUT: %impl_witness: = impl_witness (@impl.5a3.%Op.decl) [concrete = constants.%impl_witness] +// CHECK:STDOUT: %impl_witness: = impl_witness (@impl.5a3.%Op.decl) [concrete = constants.%impl_witness.40c] // CHECK:STDOUT: %TestOp.decl: %TestOp.type = fn_decl @TestOp [concrete = constants.%TestOp] { // CHECK:STDOUT: %a.patt: %C = binding_pattern a // CHECK:STDOUT: %a.param_patt: %C = value_param_pattern %a.patt, runtime_param0 @@ -120,7 +120,7 @@ fn TestOp(a: C) -> C { // CHECK:STDOUT: fn @TestOp(%a.param_patt: %C) -> %return.param_patt: %C { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %a.ref: %C = name_ref a, %a -// CHECK:STDOUT: %impl.elem0: %.784 = impl_witness_access constants.%impl_witness, element0 [concrete = constants.%Op.bf2] +// CHECK:STDOUT: %impl.elem0: %.784 = impl_witness_access constants.%impl_witness.40c, element0 [concrete = constants.%Op.bf2] // CHECK:STDOUT: %bound_method: = bound_method %a.ref, %impl.elem0 // CHECK:STDOUT: %.loc23: ref %C = splice_block %return {} // CHECK:STDOUT: %Op.call: init %C = call %bound_method(%a.ref) to %.loc23 diff --git a/toolchain/check/testdata/struct/import.carbon b/toolchain/check/testdata/struct/import.carbon index 548a4988ed4f..f16359252454 100644 --- a/toolchain/check/testdata/struct/import.carbon +++ b/toolchain/check/testdata/struct/import.carbon @@ -322,7 +322,7 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: } // CHECK:STDOUT: %Implicit.import_ref.a11: %struct_type.a.b.5ca = import_ref Implicit//default, loc8_9, loaded [symbolic = @C.%S (constants.%S)] // CHECK:STDOUT: %Implicit.import_ref.8f2: = import_ref Implicit//default, loc8_34, loaded [concrete = constants.%complete_type.357] -// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1147 [no loc], unloaded +// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1176 [no loc], unloaded // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -497,7 +497,7 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: } // CHECK:STDOUT: %Implicit.import_ref.a11: %struct_type.a.b = import_ref Implicit//default, loc8_9, loaded [symbolic = @C.%S (constants.%S)] // CHECK:STDOUT: %Implicit.import_ref.8f2: = import_ref Implicit//default, loc8_34, loaded [concrete = constants.%complete_type.357] -// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1147 [no loc], unloaded +// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1176 [no loc], unloaded // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -613,7 +613,7 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: } // CHECK:STDOUT: %Implicit.import_ref.a11: %struct_type.a.b.5ca = import_ref Implicit//default, loc8_9, loaded [symbolic = @C.%S (constants.%S)] // CHECK:STDOUT: %Implicit.import_ref.8f2: = import_ref Implicit//default, loc8_34, loaded [concrete = constants.%complete_type.357] -// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1147 [no loc], unloaded +// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1176 [no loc], unloaded // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { diff --git a/toolchain/check/testdata/tuple/access/fail_negative_indexing.carbon b/toolchain/check/testdata/tuple/access/fail_negative_indexing.carbon index 17ed689a0b42..3b3db61e1b99 100644 --- a/toolchain/check/testdata/tuple/access/fail_negative_indexing.carbon +++ b/toolchain/check/testdata/tuple/access/fail_negative_indexing.carbon @@ -42,10 +42,10 @@ var b: i32 = a.(-10); // CHECK:STDOUT: %tuple: %tuple.type.d07 = tuple_value (%int_12.1e1, %int_6.e56) [concrete] // CHECK:STDOUT: %int_10: Core.IntLiteral = int_value 10 [concrete] // CHECK:STDOUT: %impl_witness.0f6: = impl_witness (imports.%Core.import_ref.c15) [concrete] -// CHECK:STDOUT: %Op.type.e42: type = fn_type @Op.13 [concrete] +// CHECK:STDOUT: %Op.type.e42: type = fn_type @Op.14 [concrete] // CHECK:STDOUT: %Negate.facet: %Negate.type = facet_value Core.IntLiteral, %impl_witness.0f6 [concrete] // CHECK:STDOUT: %.45d: type = fn_type_with_self_type %Op.type.e42, %Negate.facet [concrete] -// CHECK:STDOUT: %Op.type.1be: type = fn_type @Op.14 [concrete] +// CHECK:STDOUT: %Op.type.1be: type = fn_type @Op.15 [concrete] // CHECK:STDOUT: %Op.bba: %Op.type.1be = struct_value () [concrete] // CHECK:STDOUT: %Op.bound: = bound_method %int_10, %Op.bba [concrete] // CHECK:STDOUT: %int_-10: Core.IntLiteral = int_value -10 [concrete] diff --git a/toolchain/check/testdata/tuple/import.carbon b/toolchain/check/testdata/tuple/import.carbon index e81100914996..1684b507ce1b 100644 --- a/toolchain/check/testdata/tuple/import.carbon +++ b/toolchain/check/testdata/tuple/import.carbon @@ -351,7 +351,7 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: } // CHECK:STDOUT: %Implicit.import_ref.554: %tuple.type.c2c = import_ref Implicit//default, loc7_9, loaded [symbolic = @C.%X (constants.%X)] // CHECK:STDOUT: %Implicit.import_ref.8f2: = import_ref Implicit//default, loc7_26, loaded [concrete = constants.%complete_type.357] -// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1182 [no loc], unloaded +// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1211 [no loc], unloaded // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -542,7 +542,7 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: } // CHECK:STDOUT: %Implicit.import_ref.554: %tuple.type.c2c = import_ref Implicit//default, loc7_9, loaded [symbolic = @C.%X (constants.%X)] // CHECK:STDOUT: %Implicit.import_ref.8f2: = import_ref Implicit//default, loc7_26, loaded [concrete = constants.%complete_type.357] -// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1182 [no loc], unloaded +// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1211 [no loc], unloaded // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -659,7 +659,7 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: } // CHECK:STDOUT: %Implicit.import_ref.554: %tuple.type.c2c = import_ref Implicit//default, loc7_9, loaded [symbolic = @C.%X (constants.%X)] // CHECK:STDOUT: %Implicit.import_ref.8f2: = import_ref Implicit//default, loc7_26, loaded [concrete = constants.%complete_type.357] -// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1182 [no loc], unloaded +// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1211 [no loc], unloaded // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { diff --git a/toolchain/check/testdata/where_expr/equal_rewrite.carbon b/toolchain/check/testdata/where_expr/equal_rewrite.carbon index 8f205a545082..916c3f411434 100644 --- a/toolchain/check/testdata/where_expr/equal_rewrite.carbon +++ b/toolchain/check/testdata/where_expr/equal_rewrite.carbon @@ -1189,8 +1189,8 @@ let K: (E where .F = .Self.G) = bool; // CHECK:STDOUT: %.Self.as_wit.cef: = facet_access_witness %.Self.9aa [symbolic_self] // CHECK:STDOUT: %impl.elem0.51b: type = impl_witness_access %.Self.as_wit.cef, element0 [symbolic_self] // CHECK:STDOUT: %N_where.type: type = facet_type <@N where %impl.elem0.51b = %empty_struct_type> [concrete] -// CHECK:STDOUT: %T.patt: %N_where.type = symbolic_binding_pattern T, 0 [symbolic] -// CHECK:STDOUT: %T: %N_where.type = bind_symbolic_name T, 0 [symbolic] +// CHECK:STDOUT: %T.patt.dbc: %N_where.type = symbolic_binding_pattern T, 0 [symbolic] +// CHECK:STDOUT: %T.7ae: %N_where.type = bind_symbolic_name T, 0 [symbolic] // CHECK:STDOUT: %Bool.type: type = fn_type @Bool [concrete] // CHECK:STDOUT: %Bool: %Bool.type = struct_value () [concrete] // CHECK:STDOUT: %NestedRewrite.type: type = fn_type @NestedRewrite [concrete] @@ -1225,7 +1225,7 @@ let K: (E where .F = .Self.G) = bool; // CHECK:STDOUT: %Main.import_ref.169 = import_ref Main//equal_constraint, inst17 [no loc], unloaded // CHECK:STDOUT: %Main.import_ref.020 = import_ref Main//equal_constraint, loc5_8, unloaded // CHECK:STDOUT: %Main.P = import_ref Main//equal_constraint, P, unloaded -// CHECK:STDOUT: %Main.import_ref.bdf: %N_where.type = import_ref Main//equal_constraint, loc8_10, loaded [symbolic = @Equal.1.%T (constants.%T)] +// CHECK:STDOUT: %Main.import_ref.bdf: %N_where.type = import_ref Main//equal_constraint, loc8_10, loaded [symbolic = @Equal.1.%T (constants.%T.7ae)] // CHECK:STDOUT: %Main.import_ref.b61 = import_ref Main//nested_rewrites, inst17 [no loc], unloaded // CHECK:STDOUT: %Main.import_ref.91a = import_ref Main//nested_rewrites, loc5_8, unloaded // CHECK:STDOUT: %Main.import_ref.55d = import_ref Main//nested_rewrites, loc6_8, unloaded @@ -1276,8 +1276,8 @@ let K: (E where .F = .Self.G) = bool; // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @Equal.1(imports.%Main.import_ref.bdf: %N_where.type) [from "equal_constraint.carbon"] { -// CHECK:STDOUT: %T: %N_where.type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)] -// CHECK:STDOUT: %T.patt: %N_where.type = symbolic_binding_pattern T, 0 [symbolic = %T.patt (constants.%T.patt)] +// CHECK:STDOUT: %T: %N_where.type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T.7ae)] +// CHECK:STDOUT: %T.patt: %N_where.type = symbolic_binding_pattern T, 0 [symbolic = %T.patt (constants.%T.patt.dbc)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%T.param_patt: %N_where.type); // CHECK:STDOUT: } @@ -1289,9 +1289,9 @@ let K: (E where .F = .Self.G) = bool; // CHECK:STDOUT: fn(%D.param_patt: %A_where.type.791); // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @Equal.1(constants.%T) { -// CHECK:STDOUT: %T => constants.%T -// CHECK:STDOUT: %T.patt => constants.%T +// CHECK:STDOUT: specific @Equal.1(constants.%T.7ae) { +// CHECK:STDOUT: %T => constants.%T.7ae +// CHECK:STDOUT: %T.patt => constants.%T.7ae // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @NestedRewrite(constants.%D) { diff --git a/toolchain/check/type_completion.cpp b/toolchain/check/type_completion.cpp index 77d0d6f45673..bcab9f0b033b 100644 --- a/toolchain/check/type_completion.cpp +++ b/toolchain/check/type_completion.cpp @@ -318,7 +318,11 @@ auto TypeCompleter::AddNestedIncompleteTypes(SemIR::Inst type_inst) -> bool { } // TODO: Sort and deduplicate result.required_interfaces. For now, we have // at most one. - CARBON_CHECK(result.required_interfaces.size() <= 1); + if (result.required_interfaces.size() > 1) { + context_.TODO(loc_, + "FacetType with more than one required interface. Sort " + "and deduplicate"); + } // TODO: Distinguish interfaces that are required but would not be // implemented, such as those from `where .Self impls I`. diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index b895f9dcf11a..d5e72449730a 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -448,11 +448,14 @@ CARBON_DIAGNOSTIC_KIND(AliasRequiresNameRef) CARBON_DIAGNOSTIC_KIND(ImplsOnNonFacetType) CARBON_DIAGNOSTIC_KIND(WhereOnNonFacetType) -// Facet type resolution +// Facet type resolution. CARBON_DIAGNOSTIC_KIND(AssociatedConstantNotConstantAfterConversion) CARBON_DIAGNOSTIC_KIND(AssociatedConstantWithDifferentValues) CARBON_DIAGNOSTIC_KIND(RewriteForAssociatedFunction) +// Facet type combination. +CARBON_DIAGNOSTIC_KIND(FacetTypeRequiredForTypeAndOperator) + // Pattern matching diagnostics. CARBON_DIAGNOSTIC_KIND(TuplePatternSizeDoesntMatchLiteral) diff --git a/toolchain/lower/handle_call.cpp b/toolchain/lower/handle_call.cpp index 6c9627a5d6f2..31b0913f8e40 100644 --- a/toolchain/lower/handle_call.cpp +++ b/toolchain/lower/handle_call.cpp @@ -205,6 +205,11 @@ static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id, return; } + case SemIR::BuiltinFunctionKind::TypeAnd: { + context.SetLocal(inst_id, context.GetTypeAsValue()); + return; + } + case SemIR::BuiltinFunctionKind::BoolMakeType: case SemIR::BuiltinFunctionKind::FloatMakeType: case SemIR::BuiltinFunctionKind::IntLiteralMakeType: diff --git a/toolchain/sem_ir/builtin_function_kind.cpp b/toolchain/sem_ir/builtin_function_kind.cpp index 0e8f7d80a3ba..7a070b1731eb 100644 --- a/toolchain/sem_ir/builtin_function_kind.cpp +++ b/toolchain/sem_ir/builtin_function_kind.cpp @@ -109,6 +109,22 @@ struct AnyFloat { } }; +// Constraint that requires the type to be the type type. +using Type = BuiltinType; + +// Constraint that requires the type to be a type value, whose type is type +// type. Also accepts symbolic constant value types. +struct AnyType { + static auto Check(const File& sem_ir, ValidateState& state, TypeId type_id) + -> bool { + if (BuiltinType::Check(sem_ir, state, type_id)) { + return true; + } + return sem_ir.types().GetAsInst(type_id).type_id() == + TypeType::SingletonTypeId; + } +}; + // Checks that the specified type matches the given type constraint. template auto Check(const File& sem_ir, ValidateState& state, TypeId type_id) -> bool { @@ -130,9 +146,6 @@ auto Check(const File& sem_ir, ValidateState& state, TypeId type_id) -> bool { return false; } -// Constraint that requires the type to be the type type. -using Type = BuiltinType; - } // namespace // Validates that this builtin has a signature matching the specified signature. @@ -394,6 +407,10 @@ constexpr BuiltinInfo BoolEq = {"bool.eq", constexpr BuiltinInfo BoolNeq = {"bool.neq", ValidateSignatureBool>}; +// "type.and": facet type combination. +constexpr BuiltinInfo TypeAnd = { + "type.and", ValidateSignatureAnyType>}; + } // namespace BuiltinFunctionInfo CARBON_DEFINE_ENUM_CLASS_NAMES(BuiltinFunctionKind) = { @@ -495,6 +512,9 @@ auto BuiltinFunctionKind::IsCompTimeOnly(const File& sem_ir, // literal types. See AnyIntLiteralTypes comment for explanation. return AnyIntLiteralTypes(sem_ir, arg_ids, return_type_id); + case TypeAnd: + return true; + default: // TODO: Should the sized MakeType functions be compile-time only? We // can't produce diagnostics for bad sizes at runtime. diff --git a/toolchain/sem_ir/builtin_function_kind.def b/toolchain/sem_ir/builtin_function_kind.def index 6c224f2fa1cb..235c56f7cc95 100644 --- a/toolchain/sem_ir/builtin_function_kind.def +++ b/toolchain/sem_ir/builtin_function_kind.def @@ -84,4 +84,7 @@ CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(FloatGreaterEq) CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(BoolEq) CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(BoolNeq) +// Facet type combination. +CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(TypeAnd) + #undef CARBON_SEM_IR_BUILTIN_FUNCTION_KIND diff --git a/toolchain/sem_ir/facet_type_info.h b/toolchain/sem_ir/facet_type_info.h index a00687c30fb2..ba7c8303885c 100644 --- a/toolchain/sem_ir/facet_type_info.h +++ b/toolchain/sem_ir/facet_type_info.h @@ -25,6 +25,20 @@ constexpr SpecificInterface SpecificInterface::None = { .interface_id = InterfaceId::None, .specific_id = SpecificId::None}; struct FacetTypeInfo : Printable { + // Returns a FacetTypeInfo that combines `lhs` and `rhs`. It is not + // canonicalized, so that it can be further modified by the caller if desired. + static auto Combine(const FacetTypeInfo& lhs, const FacetTypeInfo& rhs) + -> FacetTypeInfo { + FacetTypeInfo info = {.other_requirements = false}; + llvm::append_range(info.impls_constraints, lhs.impls_constraints); + llvm::append_range(info.impls_constraints, rhs.impls_constraints); + llvm::append_range(info.rewrite_constraints, lhs.rewrite_constraints); + llvm::append_range(info.rewrite_constraints, rhs.rewrite_constraints); + info.other_requirements |= lhs.other_requirements; + info.other_requirements |= rhs.other_requirements; + return info; + } + // TODO: Need to switch to a processed, canonical form, that can support facet // type equality as defined by // https://github.com/carbon-language/carbon-lang/issues/2409.