Basic check support for adapters. (#3874)

No support is provided yet for converting between a type and an adapter
for that type.
This commit is contained in:
Richard Smith
2024-04-10 09:57:48 +00:00
committed by GitHub
parent e8430dda81
commit 28ceb4dd4e
19 changed files with 1642 additions and 43 deletions
+1
View File
@@ -950,6 +950,7 @@ class TypeCompleter {
auto BuildValueRepr(SemIR::TypeId type_id, SemIR::Inst inst) const
-> SemIR::ValueRepr {
CARBON_KIND_SWITCH(inst) {
case SemIR::AdaptDecl::Kind:
case SemIR::AddrOf::Kind:
case SemIR::AddrPattern::Kind:
case SemIR::ArrayIndex::Kind:
+1
View File
@@ -66,6 +66,7 @@ struct DeclState {
// The kind of declaration.
enum DeclKind : int8_t {
FileScope,
Adapt,
Alias,
Base,
Class,
+1
View File
@@ -901,6 +901,7 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
}
// These cases are either not expressions or not constant.
case SemIR::AdaptDecl::Kind:
case SemIR::AddrPattern::Kind:
case SemIR::Assign::Kind:
case SemIR::BindName::Kind:
+152 -32
View File
@@ -9,6 +9,17 @@
namespace Carbon::Check {
// If `type_id` is a class type, get its corresponding `SemIR::Class` object.
// Otherwise returns `nullptr`.
static auto TryGetAsClass(Context& context, SemIR::TypeId type_id)
-> SemIR::Class* {
auto class_type = context.types().TryGetAs<SemIR::ClassType>(type_id);
if (!class_type) {
return nullptr;
}
return &context.classes().Get(class_type->class_id);
}
auto HandleClassIntroducer(Context& context, Parse::ClassIntroducerId node_id)
-> bool {
// Create an instruction block to hold the instructions created as part of the
@@ -172,15 +183,113 @@ auto HandleClassDefinitionStart(Context& context,
return true;
}
auto HandleAdaptIntroducer(Context& /*context*/,
// Diagnoses a class-specific declaration appearing outside a class.
static auto DiagnoseClassSpecificDeclOutsideClass(Context& context,
SemIRLoc loc,
Lex::TokenKind tok) -> void {
CARBON_DIAGNOSTIC(ClassSpecificDeclOutsideClass, Error,
"`{0}` declaration can only be used in a class.",
Lex::TokenKind);
context.emitter().Emit(loc, ClassSpecificDeclOutsideClass, tok);
}
// Returns the declaration of the immediately-enclosing class scope, or
// diagonses if there isn't one.
static auto GetEnclosingClassOrDiagnose(Context& context, SemIRLoc loc,
Lex::TokenKind tok)
-> std::optional<SemIR::ClassDecl> {
auto class_scope = context.GetCurrentScopeAs<SemIR::ClassDecl>();
if (!class_scope) {
DiagnoseClassSpecificDeclOutsideClass(context, loc, tok);
}
return class_scope;
}
// Diagnoses a class-specific declaration that is repeated within a class, but
// is not permitted to be repeated.
static auto DiagnoseClassSpecificDeclRepeated(Context& context,
SemIRLoc new_loc,
SemIRLoc prev_loc,
Lex::TokenKind tok) -> void {
CARBON_DIAGNOSTIC(ClassSpecificDeclRepeated, Error,
"Multiple `{0}` declarations in class.{1}", Lex::TokenKind,
std::string);
const llvm::StringRef extra = tok == Lex::TokenKind::Base
? " Multiple inheritance is not permitted."
: "";
CARBON_DIAGNOSTIC(ClassSpecificDeclPrevious, Note,
"Previous `{0}` declaration is here.", Lex::TokenKind);
context.emitter()
.Build(new_loc, ClassSpecificDeclRepeated, tok, extra.str())
.Note(prev_loc, ClassSpecificDeclPrevious, tok)
.Emit();
}
auto HandleAdaptIntroducer(Context& context,
Parse::AdaptIntroducerId /*node_id*/) -> bool {
context.decl_state_stack().Push(DeclState::Adapt);
return true;
}
auto HandleAdaptDecl(Context& context, Parse::AdaptDeclId /*node_id*/) -> bool {
auto adapted_expr_id = context.node_stack().PopExpr();
(void)adapted_expr_id;
// TODO: Process the `adapt` declaration.
auto HandleAdaptDecl(Context& context, Parse::AdaptDeclId node_id) -> bool {
auto [adapted_type_node, adapted_type_expr_id] =
context.node_stack().PopExprWithNodeId();
// Process modifiers. `extend` is permitted, no others are allowed.
LimitModifiersOnDecl(context, KeywordModifierSet::Extend,
Lex::TokenKind::Adapt);
auto modifiers = context.decl_state_stack().innermost().modifier_set;
context.decl_state_stack().Pop(DeclState::Adapt);
auto enclosing_class_decl =
GetEnclosingClassOrDiagnose(context, node_id, Lex::TokenKind::Adapt);
if (!enclosing_class_decl) {
return true;
}
auto& class_info = context.classes().Get(enclosing_class_decl->class_id);
if (class_info.adapt_id.is_valid()) {
DiagnoseClassSpecificDeclRepeated(context, node_id, class_info.adapt_id,
Lex::TokenKind::Adapt);
return true;
}
auto adapted_type_id = ExprAsType(context, node_id, adapted_type_expr_id);
adapted_type_id = context.AsCompleteType(adapted_type_id, [&] {
CARBON_DIAGNOSTIC(IncompleteTypeInAdaptDecl, Error,
"Adapted type `{0}` is an incomplete type.",
SemIR::TypeId);
return context.emitter().Build(node_id, IncompleteTypeInAdaptDecl,
adapted_type_id);
});
// Build a SemIR representation for the declaration.
class_info.adapt_id =
context.AddInst({node_id, SemIR::AdaptDecl{adapted_type_id}});
// Extend the class scope with the adapted type's scope if requested.
if (!!(modifiers & KeywordModifierSet::Extend)) {
auto extended_scope_id = SemIR::NameScopeId::Invalid;
if (adapted_type_id == SemIR::TypeId::Error) {
// Recover by not extending any scope. We instead set has_error to true
// below.
} else if (auto* adapted_class_info =
TryGetAsClass(context, adapted_type_id)) {
extended_scope_id = adapted_class_info->scope_id;
CARBON_CHECK(adapted_class_info->scope_id.is_valid())
<< "Complete class should have a scope";
} else {
// TODO: Accept any type that has a scope.
context.TODO(node_id, "extending non-class type");
}
auto& class_scope = context.name_scopes().Get(class_info.scope_id);
if (extended_scope_id.is_valid()) {
class_scope.extended_scopes.push_back(extended_scope_id);
} else {
class_scope.has_error = true;
}
}
return true;
}
@@ -208,17 +317,6 @@ constexpr BaseInfo BaseInfo::Error = {.type_id = SemIR::TypeId::Error,
.scope_id = SemIR::NameScopeId::Invalid};
} // namespace
// If `type_id` is a class type, get its corresponding `SemIR::Class` object.
// Otherwise returns `nullptr`.
static auto TryGetAsClass(Context& context, SemIR::TypeId type_id)
-> SemIR::Class* {
auto class_type = context.types().TryGetAs<SemIR::ClassType>(type_id);
if (!class_type) {
return nullptr;
}
return &context.classes().Get(class_type->class_id);
}
// Diagnoses an attempt to derive from a final type.
static auto DiagnoseBaseIsFinal(Context& context, Parse::NodeId node_id,
SemIR::TypeId base_type_id) -> void {
@@ -268,7 +366,7 @@ auto HandleBaseDecl(Context& context, Parse::BaseDeclId node_id) -> bool {
auto [base_type_node_id, base_type_expr_id] =
context.node_stack().PopExprWithNodeId();
// Process modifiers. `extend` is required, none others are allowed.
// Process modifiers. `extend` is required, no others are allowed.
LimitModifiersOnDecl(context, KeywordModifierSet::Extend,
Lex::TokenKind::Base);
auto modifiers = context.decl_state_stack().innermost().modifier_set;
@@ -279,25 +377,16 @@ auto HandleBaseDecl(Context& context, Parse::BaseDeclId node_id) -> bool {
}
context.decl_state_stack().Pop(DeclState::Base);
auto enclosing_class_decl = context.GetCurrentScopeAs<SemIR::ClassDecl>();
auto enclosing_class_decl =
GetEnclosingClassOrDiagnose(context, node_id, Lex::TokenKind::Base);
if (!enclosing_class_decl) {
CARBON_DIAGNOSTIC(BaseOutsideClass, Error,
"`base` declaration can only be used in a class.");
context.emitter().Emit(node_id, BaseOutsideClass);
return true;
}
auto& class_info = context.classes().Get(enclosing_class_decl->class_id);
if (class_info.base_id.is_valid()) {
CARBON_DIAGNOSTIC(BaseRepeated, Error,
"Multiple `base` declarations in class. Multiple "
"inheritance is not permitted.");
CARBON_DIAGNOSTIC(BasePrevious, Note,
"Previous `base` declaration is here.");
context.emitter()
.Build(node_id, BaseRepeated)
.Note(class_info.base_id, BasePrevious)
.Emit();
DiagnoseClassSpecificDeclRepeated(context, node_id, class_info.base_id,
Lex::TokenKind::Base);
return true;
}
@@ -316,6 +405,7 @@ auto HandleBaseDecl(Context& context, Parse::BaseDeclId node_id) -> bool {
// Add a corresponding field to the object representation of the class.
// TODO: Consider whether we want to use `partial T` here.
// TODO: Should we diagnose if there are already any fields?
context.args_type_info_stack().AddInstId(context.AddInstInNoBlock(
{node_id,
SemIR::StructTypeField{SemIR::NameId::Base, base_info.type_id}}));
@@ -345,9 +435,39 @@ auto HandleClassDefinition(Context& context,
context.node_stack().Pop<Parse::NodeKind::ClassDefinitionStart>();
context.inst_block_stack().Pop();
// The class type is now fully defined.
// The class type is now fully defined. Compute its object representation.
auto& class_info = context.classes().Get(class_id);
class_info.object_repr_id = context.GetStructType(fields_id);
if (class_info.adapt_id.is_valid()) {
class_info.object_repr_id = SemIR::TypeId::Error;
if (class_info.base_id.is_valid()) {
CARBON_DIAGNOSTIC(AdaptWithBase, Error,
"Adapter cannot have a base class.");
CARBON_DIAGNOSTIC(AdaptBaseHere, Note, "`base` declaration is here.");
context.emitter()
.Build(class_info.adapt_id, AdaptWithBase)
.Note(class_info.base_id, AdaptBaseHere)
.Emit();
} else if (!context.inst_blocks().Get(fields_id).empty()) {
auto first_field_id = context.inst_blocks().Get(fields_id).front();
CARBON_DIAGNOSTIC(AdaptWithFields, Error, "Adapter cannot have fields.");
CARBON_DIAGNOSTIC(AdaptFieldHere, Note,
"First field declaration is here.");
context.emitter()
.Build(class_info.adapt_id, AdaptWithFields)
.Note(first_field_id, AdaptFieldHere)
.Emit();
} else {
// The object representation of the adapter is the adapted type.
// TODO: If the adapted type is a class, should we use its object
// representation type instead?
class_info.object_repr_id =
context.insts()
.GetAs<SemIR::AdaptDecl>(class_info.adapt_id)
.adapted_type_id;
}
} else {
class_info.object_repr_id = context.GetStructType(fields_id);
}
// The decl_name_stack and scopes are popped by `ProcessNodeIds`.
return true;
+146
View File
@@ -0,0 +1,146 @@
// 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
//
// AUTOUPDATE
// --- basic.carbon
library "basic" api;
class SomeClass {
var a: i32;
var b: i32;
}
class SomeClassAdapter {
adapt SomeClass;
}
class StructAdapter {
adapt {.a: i32, .b: i32};
}
// --- fail_not_extend.carbon
library "fail_not_extend" api;
class Adapted {
fn F();
}
class AdaptNotExtend {
adapt Adapted;
}
fn F(a: AdaptNotExtend) {
// `Adapted` is not extended, so lookup for `F` finds nothing.
// CHECK:STDERR: fail_not_extend.carbon:[[@LINE+3]]:3: ERROR: Name `F` not found.
// CHECK:STDERR: a.F();
// CHECK:STDERR: ^~~
a.F();
}
// CHECK:STDOUT: --- basic.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %SomeClass: type = class_type @SomeClass [template]
// CHECK:STDOUT: %.1: type = unbound_element_type SomeClass, i32 [template]
// CHECK:STDOUT: %.2: type = struct_type {.a: i32, .b: i32} [template]
// CHECK:STDOUT: %SomeClassAdapter: type = class_type @SomeClassAdapter [template]
// CHECK:STDOUT: %.3: type = ptr_type {.a: i32, .b: i32} [template]
// CHECK:STDOUT: %StructAdapter: type = class_type @StructAdapter [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .SomeClass = %SomeClass.decl
// CHECK:STDOUT: .SomeClassAdapter = %SomeClassAdapter.decl
// CHECK:STDOUT: .StructAdapter = %StructAdapter.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %SomeClass.decl: type = class_decl @SomeClass [template = constants.%SomeClass] {}
// CHECK:STDOUT: %SomeClassAdapter.decl: type = class_decl @SomeClassAdapter [template = constants.%SomeClassAdapter] {}
// CHECK:STDOUT: %StructAdapter.decl: type = class_decl @StructAdapter [template = constants.%StructAdapter] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @SomeClass {
// CHECK:STDOUT: %.loc5: <unbound element of class SomeClass> = field_decl a, element0 [template]
// CHECK:STDOUT: %.loc6: <unbound element of class SomeClass> = field_decl b, element1 [template]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%SomeClass
// CHECK:STDOUT: .a = %.loc5
// CHECK:STDOUT: .b = %.loc6
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @SomeClassAdapter {
// CHECK:STDOUT: %SomeClass.ref: type = name_ref SomeClass, file.%SomeClass.decl [template = constants.%SomeClass]
// CHECK:STDOUT: adapt_decl SomeClass
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%SomeClassAdapter
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @StructAdapter {
// CHECK:STDOUT: %.loc14: type = struct_type {.a: i32, .b: i32} [template = constants.%.2]
// CHECK:STDOUT: adapt_decl {.a: i32, .b: i32}
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%StructAdapter
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_not_extend.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Adapted: type = class_type @Adapted [template]
// CHECK:STDOUT: %.1: type = struct_type {} [template]
// CHECK:STDOUT: %AdaptNotExtend: type = class_type @AdaptNotExtend [template]
// CHECK:STDOUT: %.2: type = tuple_type () [template]
// CHECK:STDOUT: %.3: type = ptr_type {} [template]
// CHECK:STDOUT: %.4: type = ptr_type Adapted [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .Adapted = %Adapted.decl
// CHECK:STDOUT: .AdaptNotExtend = %AdaptNotExtend.decl
// CHECK:STDOUT: .F = %F
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %Adapted.decl: type = class_decl @Adapted [template = constants.%Adapted] {}
// CHECK:STDOUT: %AdaptNotExtend.decl: type = class_decl @AdaptNotExtend [template = constants.%AdaptNotExtend] {}
// CHECK:STDOUT: %F: <function> = fn_decl @F.2 [template] {
// CHECK:STDOUT: %AdaptNotExtend.ref: type = name_ref AdaptNotExtend, %AdaptNotExtend.decl [template = constants.%AdaptNotExtend]
// CHECK:STDOUT: %a.loc12_6.1: AdaptNotExtend = param a
// CHECK:STDOUT: @F.2.%a: AdaptNotExtend = bind_name a, %a.loc12_6.1
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @Adapted {
// CHECK:STDOUT: %F: <function> = fn_decl @F.1 [template] {}
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%Adapted
// CHECK:STDOUT: .F = %F
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @AdaptNotExtend {
// CHECK:STDOUT: %Adapted.ref: type = name_ref Adapted, file.%Adapted.decl [template = constants.%Adapted]
// CHECK:STDOUT: adapt_decl Adapted
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%AdaptNotExtend
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.1();
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.2(%a: AdaptNotExtend) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %a.ref: AdaptNotExtend = name_ref a, %a
// CHECK:STDOUT: %F.ref: <error> = name_ref F, <error> [template = <error>]
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
+314
View File
@@ -0,0 +1,314 @@
// 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
//
// AUTOUPDATE
// --- basic.carbon
library "basic" api;
class SomeClassAdapter;
class SomeClass {
var a: i32;
var b: i32;
fn StaticMemberFunction();
fn AdapterMethod[self: SomeClassAdapter]();
}
class SomeClassAdapter {
extend adapt SomeClass;
}
fn TestStaticMemberFunction(a: SomeClassAdapter) {
a.StaticMemberFunction();
}
fn TestAdapterMethod(a: SomeClassAdapter) {
a.AdapterMethod();
}
// --- fail_todo_method_access.carbon
library "fail_todo_method_access" api;
class SomeClass {
fn F[self: Self]();
}
class SomeClassAdapter {
extend adapt SomeClass;
}
fn F(a: SomeClassAdapter) {
// CHECK:STDERR: fail_todo_method_access.carbon:[[@LINE+7]]:3: ERROR: Cannot implicitly convert from `SomeClassAdapter` to `SomeClass`.
// CHECK:STDERR: a.F();
// CHECK:STDERR: ^~~~
// CHECK:STDERR: fail_todo_method_access.carbon:[[@LINE-11]]:8: Initializing `self` parameter of method declared here.
// CHECK:STDERR: fn F[self: Self]();
// CHECK:STDERR: ^~~~
// CHECK:STDERR:
a.F();
}
// --- fail_todo_field_access.carbon
library "fail_todo_field_access" api;
class SomeClass {
var a: i32;
var b: i32;
}
class SomeClassAdapter {
extend adapt SomeClass;
}
fn F(a: SomeClassAdapter) -> i32 {
// CHECK:STDERR: fail_todo_field_access.carbon:[[@LINE+4]]:10: ERROR: Cannot implicitly convert from `SomeClassAdapter` to `SomeClass`.
// CHECK:STDERR: return a.b;
// CHECK:STDERR: ^~~
// CHECK:STDERR:
return a.b;
}
// --- fail_todo_adapt_non_class.carbon
library "fail_todo_adapt_non_class" api;
class StructAdapter {
// CHECK:STDERR: fail_todo_adapt_non_class.carbon:[[@LINE+3]]:3: ERROR: Semantics TODO: `extending non-class type`.
// CHECK:STDERR: extend adapt {.a: i32, .b: i32};
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
extend adapt {.a: i32, .b: i32};
}
// CHECK:STDOUT: --- basic.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %SomeClassAdapter: type = class_type @SomeClassAdapter [template]
// CHECK:STDOUT: %SomeClass: type = class_type @SomeClass [template]
// CHECK:STDOUT: %.1: type = unbound_element_type SomeClass, i32 [template]
// CHECK:STDOUT: %.2: type = struct_type {.a: i32, .b: i32} [template]
// CHECK:STDOUT: %.3: type = ptr_type {.a: i32, .b: i32} [template]
// CHECK:STDOUT: %.4: type = ptr_type SomeClass [template]
// CHECK:STDOUT: %.5: type = tuple_type () [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .SomeClassAdapter = %SomeClassAdapter.decl.loc4
// CHECK:STDOUT: .SomeClass = %SomeClass.decl
// CHECK:STDOUT: .TestStaticMemberFunction = %TestStaticMemberFunction
// CHECK:STDOUT: .TestAdapterMethod = %TestAdapterMethod
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %SomeClassAdapter.decl.loc4: type = class_decl @SomeClassAdapter [template = constants.%SomeClassAdapter] {}
// CHECK:STDOUT: %SomeClass.decl: type = class_decl @SomeClass [template = constants.%SomeClass] {}
// CHECK:STDOUT: %SomeClassAdapter.decl.loc15: type = class_decl @SomeClassAdapter [template = constants.%SomeClassAdapter] {}
// CHECK:STDOUT: %TestStaticMemberFunction: <function> = fn_decl @TestStaticMemberFunction [template] {
// CHECK:STDOUT: %SomeClassAdapter.ref.loc19: type = name_ref SomeClassAdapter, %SomeClassAdapter.decl.loc4 [template = constants.%SomeClassAdapter]
// CHECK:STDOUT: %a.loc19_29.1: SomeClassAdapter = param a
// CHECK:STDOUT: @TestStaticMemberFunction.%a: SomeClassAdapter = bind_name a, %a.loc19_29.1
// CHECK:STDOUT: }
// CHECK:STDOUT: %TestAdapterMethod: <function> = fn_decl @TestAdapterMethod [template] {
// CHECK:STDOUT: %SomeClassAdapter.ref.loc23: type = name_ref SomeClassAdapter, %SomeClassAdapter.decl.loc4 [template = constants.%SomeClassAdapter]
// CHECK:STDOUT: %a.loc23_22.1: SomeClassAdapter = param a
// CHECK:STDOUT: @TestAdapterMethod.%a: SomeClassAdapter = bind_name a, %a.loc23_22.1
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @SomeClassAdapter {
// CHECK:STDOUT: %SomeClass.ref: type = name_ref SomeClass, file.%SomeClass.decl [template = constants.%SomeClass]
// CHECK:STDOUT: adapt_decl SomeClass
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%SomeClassAdapter
// CHECK:STDOUT: extend name_scope2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @SomeClass {
// CHECK:STDOUT: %.loc7: <unbound element of class SomeClass> = field_decl a, element0 [template]
// CHECK:STDOUT: %.loc8: <unbound element of class SomeClass> = field_decl b, element1 [template]
// CHECK:STDOUT: %StaticMemberFunction: <function> = fn_decl @StaticMemberFunction [template] {}
// CHECK:STDOUT: %AdapterMethod: <function> = fn_decl @AdapterMethod [template] {
// CHECK:STDOUT: %SomeClassAdapter.ref: type = name_ref SomeClassAdapter, file.%SomeClassAdapter.decl.loc4 [template = constants.%SomeClassAdapter]
// CHECK:STDOUT: %self.loc12_20.1: SomeClassAdapter = param self
// CHECK:STDOUT: %self.loc12_20.2: SomeClassAdapter = bind_name self, %self.loc12_20.1
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%SomeClass
// CHECK:STDOUT: .a = %.loc7
// CHECK:STDOUT: .b = %.loc8
// CHECK:STDOUT: .StaticMemberFunction = %StaticMemberFunction
// CHECK:STDOUT: .AdapterMethod = %AdapterMethod
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @StaticMemberFunction();
// CHECK:STDOUT:
// CHECK:STDOUT: fn @AdapterMethod[@SomeClass.%self.loc12_20.2: SomeClassAdapter]();
// CHECK:STDOUT:
// CHECK:STDOUT: fn @TestStaticMemberFunction(%a: SomeClassAdapter) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %a.ref: SomeClassAdapter = name_ref a, %a
// CHECK:STDOUT: %StaticMemberFunction.ref: <function> = name_ref StaticMemberFunction, @SomeClass.%StaticMemberFunction [template = @SomeClass.%StaticMemberFunction]
// CHECK:STDOUT: %.loc20: init () = call %StaticMemberFunction.ref()
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @TestAdapterMethod(%a: SomeClassAdapter) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %a.ref: SomeClassAdapter = name_ref a, %a
// CHECK:STDOUT: %AdapterMethod.ref: <function> = name_ref AdapterMethod, @SomeClass.%AdapterMethod [template = @SomeClass.%AdapterMethod]
// CHECK:STDOUT: %.loc24_4: <bound method> = bound_method %a.ref, %AdapterMethod.ref
// CHECK:STDOUT: %.loc24_18: init () = call %.loc24_4(%a.ref)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_method_access.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %SomeClass: type = class_type @SomeClass [template]
// CHECK:STDOUT: %.1: type = struct_type {} [template]
// CHECK:STDOUT: %SomeClassAdapter: type = class_type @SomeClassAdapter [template]
// CHECK:STDOUT: %.2: type = tuple_type () [template]
// CHECK:STDOUT: %.3: type = ptr_type {} [template]
// CHECK:STDOUT: %.4: type = ptr_type SomeClass [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .SomeClass = %SomeClass.decl
// CHECK:STDOUT: .SomeClassAdapter = %SomeClassAdapter.decl
// CHECK:STDOUT: .F = %F
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %SomeClass.decl: type = class_decl @SomeClass [template = constants.%SomeClass] {}
// CHECK:STDOUT: %SomeClassAdapter.decl: type = class_decl @SomeClassAdapter [template = constants.%SomeClassAdapter] {}
// CHECK:STDOUT: %F: <function> = fn_decl @F.2 [template] {
// CHECK:STDOUT: %SomeClassAdapter.ref: type = name_ref SomeClassAdapter, %SomeClassAdapter.decl [template = constants.%SomeClassAdapter]
// CHECK:STDOUT: %a.loc12_6.1: SomeClassAdapter = param a
// CHECK:STDOUT: @F.2.%a: SomeClassAdapter = bind_name a, %a.loc12_6.1
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @SomeClass {
// CHECK:STDOUT: %F: <function> = fn_decl @F.1 [template] {
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%SomeClass [template = constants.%SomeClass]
// CHECK:STDOUT: %self.loc5_8.1: SomeClass = param self
// CHECK:STDOUT: %self.loc5_8.2: SomeClass = bind_name self, %self.loc5_8.1
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%SomeClass
// CHECK:STDOUT: .F = %F
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @SomeClassAdapter {
// CHECK:STDOUT: %SomeClass.ref: type = name_ref SomeClass, file.%SomeClass.decl [template = constants.%SomeClass]
// CHECK:STDOUT: adapt_decl SomeClass
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%SomeClassAdapter
// CHECK:STDOUT: extend name_scope2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.1[@SomeClass.%self.loc5_8.2: SomeClass]();
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.2(%a: SomeClassAdapter) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %a.ref: SomeClassAdapter = name_ref a, %a
// CHECK:STDOUT: %F.ref: <function> = name_ref F, @SomeClass.%F [template = @SomeClass.%F]
// CHECK:STDOUT: %.loc20_4: <bound method> = bound_method %a.ref, %F.ref
// CHECK:STDOUT: %.loc20_6: init () = call %.loc20_4(<invalid>) [template = <error>]
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_field_access.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %SomeClass: type = class_type @SomeClass [template]
// CHECK:STDOUT: %.1: type = unbound_element_type SomeClass, i32 [template]
// CHECK:STDOUT: %.2: type = struct_type {.a: i32, .b: i32} [template]
// CHECK:STDOUT: %SomeClassAdapter: type = class_type @SomeClassAdapter [template]
// CHECK:STDOUT: %.3: type = ptr_type {.a: i32, .b: i32} [template]
// CHECK:STDOUT: %.4: type = ptr_type SomeClass [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .SomeClass = %SomeClass.decl
// CHECK:STDOUT: .SomeClassAdapter = %SomeClassAdapter.decl
// CHECK:STDOUT: .F = %F
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %SomeClass.decl: type = class_decl @SomeClass [template = constants.%SomeClass] {}
// CHECK:STDOUT: %SomeClassAdapter.decl: type = class_decl @SomeClassAdapter [template = constants.%SomeClassAdapter] {}
// CHECK:STDOUT: %F: <function> = fn_decl @F [template] {
// CHECK:STDOUT: %SomeClassAdapter.ref: type = name_ref SomeClassAdapter, %SomeClassAdapter.decl [template = constants.%SomeClassAdapter]
// CHECK:STDOUT: %a.loc13_6.1: SomeClassAdapter = param a
// CHECK:STDOUT: @F.%a: SomeClassAdapter = bind_name a, %a.loc13_6.1
// CHECK:STDOUT: %return.var: ref i32 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @SomeClass {
// CHECK:STDOUT: %.loc5: <unbound element of class SomeClass> = field_decl a, element0 [template]
// CHECK:STDOUT: %.loc6: <unbound element of class SomeClass> = field_decl b, element1 [template]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%SomeClass
// CHECK:STDOUT: .a = %.loc5
// CHECK:STDOUT: .b = %.loc6
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @SomeClassAdapter {
// CHECK:STDOUT: %SomeClass.ref: type = name_ref SomeClass, file.%SomeClass.decl [template = constants.%SomeClass]
// CHECK:STDOUT: adapt_decl SomeClass
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%SomeClassAdapter
// CHECK:STDOUT: extend name_scope2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F(%a: SomeClassAdapter) -> i32 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %a.ref: SomeClassAdapter = name_ref a, %a
// CHECK:STDOUT: %b.ref: <unbound element of class SomeClass> = name_ref b, @SomeClass.%.loc6 [template = @SomeClass.%.loc6]
// CHECK:STDOUT: %.loc18: i32 = class_element_access <error>, element1 [template = <error>]
// CHECK:STDOUT: return <error>
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_adapt_non_class.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %StructAdapter: type = class_type @StructAdapter [template]
// CHECK:STDOUT: %.1: type = struct_type {.a: i32, .b: i32} [template]
// CHECK:STDOUT: %.2: type = ptr_type {.a: i32, .b: i32} [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .StructAdapter = %StructAdapter.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %StructAdapter.decl: type = class_decl @StructAdapter [template = constants.%StructAdapter] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @StructAdapter {
// CHECK:STDOUT: %.loc8: type = struct_type {.a: i32, .b: i32} [template = constants.%.1]
// CHECK:STDOUT: adapt_decl {.a: i32, .b: i32}
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%StructAdapter
// CHECK:STDOUT: has_error
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -0,0 +1,256 @@
// 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
//
// AUTOUPDATE
// --- fail_not_type.carbon
library "not_type" api;
class Bad {
// CHECK:STDERR: fail_not_type.carbon:[[@LINE+4]]:3: ERROR: Cannot implicitly convert from `i32` to `type`.
// CHECK:STDERR: adapt 100;
// CHECK:STDERR: ^~~~~~~~~~
// CHECK:STDERR:
adapt 100;
}
// CHECK:STDERR: fail_not_type.carbon:[[@LINE+4]]:18: ERROR: Name `F` not found.
// CHECK:STDERR: fn Use(b: Bad) { b.F(); }
// CHECK:STDERR: ^~~
// CHECK:STDERR:
fn Use(b: Bad) { b.F(); }
// --- fail_extend_not_type.carbon
library "extend_not_type" api;
class Bad {
// CHECK:STDERR: fail_extend_not_type.carbon:[[@LINE+4]]:3: ERROR: Cannot implicitly convert from `i32` to `type`.
// CHECK:STDERR: extend adapt 100;
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
// CHECK:STDERR:
extend adapt 100;
}
// No diagnostic here, we don't know what names Bad has.
fn Use(b: Bad) { b.F(); }
// --- fail_repeated.carbon
library "fail_repeated" api;
class MultipleAdapts {
adapt ();
// CHECK:STDERR: fail_repeated.carbon:[[@LINE+7]]:3: ERROR: Multiple `adapt` declarations in class.
// CHECK:STDERR: adapt {};
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_repeated.carbon:[[@LINE-4]]:3: Previous `adapt` declaration is here.
// CHECK:STDERR: adapt ();
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
adapt {};
}
class MultipleAdaptsSameType {
adapt ();
// CHECK:STDERR: fail_repeated.carbon:[[@LINE+7]]:3: ERROR: Multiple `adapt` declarations in class.
// CHECK:STDERR: adapt ();
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_repeated.carbon:[[@LINE-4]]:3: Previous `adapt` declaration is here.
// CHECK:STDERR: adapt ();
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
adapt ();
}
// --- fail_bad_scope.carbon
library "fail_bad_scope" api;
// CHECK:STDERR: fail_bad_scope.carbon:[[@LINE+4]]:1: ERROR: `adapt` declaration can only be used in a class.
// CHECK:STDERR: adapt {};
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
adapt {};
interface I {
// CHECK:STDERR: fail_bad_scope.carbon:[[@LINE+4]]:3: ERROR: `adapt` declaration can only be used in a class.
// CHECK:STDERR: adapt {};
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
adapt {};
}
class C {
interface I {
// CHECK:STDERR: fail_bad_scope.carbon:[[@LINE+3]]:5: ERROR: `adapt` declaration can only be used in a class.
// CHECK:STDERR: adapt {};
// CHECK:STDERR: ^~~~~~~~~
adapt {};
}
}
// CHECK:STDOUT: --- fail_not_type.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Bad: type = class_type @Bad [template]
// CHECK:STDOUT: %.1: i32 = int_literal 100 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .Bad = %Bad.decl
// CHECK:STDOUT: .Use = %Use
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %Bad.decl: type = class_decl @Bad [template = constants.%Bad] {}
// CHECK:STDOUT: %Use: <function> = fn_decl @Use [template] {
// CHECK:STDOUT: %Bad.ref: type = name_ref Bad, %Bad.decl [template = constants.%Bad]
// CHECK:STDOUT: %b.loc16_8.1: Bad = param b
// CHECK:STDOUT: @Use.%b: Bad = bind_name b, %b.loc16_8.1
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @Bad {
// CHECK:STDOUT: %.loc9: i32 = int_literal 100 [template = constants.%.1]
// CHECK:STDOUT: adapt_decl <error>
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%Bad
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Use(%b: Bad) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %b.ref: Bad = name_ref b, %b
// CHECK:STDOUT: %F.ref: <error> = name_ref F, <error> [template = <error>]
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_extend_not_type.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Bad: type = class_type @Bad [template]
// CHECK:STDOUT: %.1: i32 = int_literal 100 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .Bad = %Bad.decl
// CHECK:STDOUT: .Use = %Use
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %Bad.decl: type = class_decl @Bad [template = constants.%Bad] {}
// CHECK:STDOUT: %Use: <function> = fn_decl @Use [template] {
// CHECK:STDOUT: %Bad.ref: type = name_ref Bad, %Bad.decl [template = constants.%Bad]
// CHECK:STDOUT: %b.loc13_8.1: Bad = param b
// CHECK:STDOUT: @Use.%b: Bad = bind_name b, %b.loc13_8.1
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @Bad {
// CHECK:STDOUT: %.loc9: i32 = int_literal 100 [template = constants.%.1]
// CHECK:STDOUT: adapt_decl <error>
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%Bad
// CHECK:STDOUT: has_error
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Use(%b: Bad) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %b.ref: Bad = name_ref b, %b
// CHECK:STDOUT: %F.ref: <error> = name_ref F, <error> [template = <error>]
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_repeated.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %MultipleAdapts: type = class_type @MultipleAdapts [template]
// CHECK:STDOUT: %.1: type = tuple_type () [template]
// CHECK:STDOUT: %.2: type = struct_type {} [template]
// CHECK:STDOUT: %MultipleAdaptsSameType: type = class_type @MultipleAdaptsSameType [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .MultipleAdapts = %MultipleAdapts.decl
// CHECK:STDOUT: .MultipleAdaptsSameType = %MultipleAdaptsSameType.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %MultipleAdapts.decl: type = class_decl @MultipleAdapts [template = constants.%MultipleAdapts] {}
// CHECK:STDOUT: %MultipleAdaptsSameType.decl: type = class_decl @MultipleAdaptsSameType [template = constants.%MultipleAdaptsSameType] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @MultipleAdapts {
// CHECK:STDOUT: %.loc5_10.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc5_10.2: type = converted %.loc5_10.1, constants.%.1 [template = constants.%.1]
// CHECK:STDOUT: adapt_decl ()
// CHECK:STDOUT: %.loc13: {} = struct_literal ()
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%MultipleAdapts
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @MultipleAdaptsSameType {
// CHECK:STDOUT: %.loc17_10.1: () = tuple_literal ()
// CHECK:STDOUT: %.loc17_10.2: type = converted %.loc17_10.1, constants.%.1 [template = constants.%.1]
// CHECK:STDOUT: adapt_decl ()
// CHECK:STDOUT: %.loc25: () = tuple_literal ()
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%MultipleAdaptsSameType
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_bad_scope.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: type = struct_type {} [template]
// CHECK:STDOUT: %.2: type = interface_type @I.1 [template]
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.3: type = interface_type @I.2 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .I = %I.decl
// CHECK:STDOUT: .C = %C.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %.loc8: {} = struct_literal ()
// CHECK:STDOUT: %I.decl: type = interface_decl @I.1 [template = constants.%.2] {}
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: interface @I.1 {
// CHECK:STDOUT: %Self: I = bind_symbolic_name Self [symbolic]
// CHECK:STDOUT: %.loc15: {} = struct_literal ()
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = %Self
// CHECK:STDOUT: witness = ()
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: interface @I.2 {
// CHECK:STDOUT: %Self: I = bind_symbolic_name Self [symbolic]
// CHECK:STDOUT: %.loc23: {} = struct_literal ()
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = %Self
// CHECK:STDOUT: witness = ()
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: %I.decl: type = interface_decl @I.2 [template = constants.%.3] {}
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: .I = %I.decl
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -0,0 +1,50 @@
// 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
//
// AUTOUPDATE
// --- fail_incomplete_type.carbon
library "incomplete_type" api;
class Incomplete;
class AdaptIncomplete {
// CHECK:STDERR: fail_incomplete_type.carbon:[[@LINE+6]]:3: ERROR: Adapted type `Incomplete` is an incomplete type.
// CHECK:STDERR: adapt Incomplete;
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_incomplete_type.carbon:[[@LINE-6]]:1: Class was forward declared here.
// CHECK:STDERR: class Incomplete;
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
adapt Incomplete;
}
// CHECK:STDOUT: --- fail_incomplete_type.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Incomplete: type = class_type @Incomplete [template]
// CHECK:STDOUT: %AdaptIncomplete: type = class_type @AdaptIncomplete [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .Incomplete = %Incomplete.decl
// CHECK:STDOUT: .AdaptIncomplete = %AdaptIncomplete.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %Incomplete.decl: type = class_decl @Incomplete [template = constants.%Incomplete] {}
// CHECK:STDOUT: %AdaptIncomplete.decl: type = class_decl @AdaptIncomplete [template = constants.%AdaptIncomplete] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @Incomplete;
// CHECK:STDOUT:
// CHECK:STDOUT: class @AdaptIncomplete {
// CHECK:STDOUT: %Incomplete.ref: type = name_ref Incomplete, file.%Incomplete.decl [template = constants.%Incomplete]
// CHECK:STDOUT: adapt_decl <error>
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%AdaptIncomplete
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -0,0 +1,133 @@
// 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
//
// AUTOUPDATE
class B {}
class C1 {
// CHECK:STDERR: fail_adapt_modifiers.carbon:[[@LINE+4]]:3: ERROR: `private` not allowed on `adapt` declaration.
// CHECK:STDERR: private adapt B;
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
private adapt B;
}
class C2 {
// CHECK:STDERR: fail_adapt_modifiers.carbon:[[@LINE+4]]:3: ERROR: `abstract` not allowed on `adapt` declaration.
// CHECK:STDERR: abstract adapt B;
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR:
abstract adapt B;
}
class C3 {
// CHECK:STDERR: fail_adapt_modifiers.carbon:[[@LINE+4]]:3: ERROR: `default` not allowed on `adapt` declaration.
// CHECK:STDERR: default adapt B;
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
default adapt B;
}
class C4 {
// CHECK:STDERR: fail_adapt_modifiers.carbon:[[@LINE+7]]:10: ERROR: `extend` repeated on declaration.
// CHECK:STDERR: extend extend adapt B;
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: fail_adapt_modifiers.carbon:[[@LINE+4]]:3: `extend` previously appeared here.
// CHECK:STDERR: extend extend adapt B;
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR:
extend extend adapt B;
}
class C5 {
// CHECK:STDERR: fail_adapt_modifiers.carbon:[[@LINE+6]]:10: ERROR: `base` not allowed on declaration with `extend`.
// CHECK:STDERR: extend base adapt B;
// CHECK:STDERR: ^~~~
// CHECK:STDERR: fail_adapt_modifiers.carbon:[[@LINE+3]]:3: `extend` previously appeared here.
// CHECK:STDERR: extend base adapt B;
// CHECK:STDERR: ^~~~~~
extend base adapt B;
}
// CHECK:STDOUT: --- fail_adapt_modifiers.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %B: type = class_type @B [template]
// CHECK:STDOUT: %.1: type = struct_type {} [template]
// CHECK:STDOUT: %C1: type = class_type @C1 [template]
// CHECK:STDOUT: %.2: type = tuple_type () [template]
// CHECK:STDOUT: %.3: type = ptr_type {} [template]
// CHECK:STDOUT: %C2: type = class_type @C2 [template]
// CHECK:STDOUT: %C3: type = class_type @C3 [template]
// CHECK:STDOUT: %C4: type = class_type @C4 [template]
// CHECK:STDOUT: %C5: type = class_type @C5 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .B = %B.decl
// CHECK:STDOUT: .C1 = %C1.decl
// CHECK:STDOUT: .C2 = %C2.decl
// CHECK:STDOUT: .C3 = %C3.decl
// CHECK:STDOUT: .C4 = %C4.decl
// CHECK:STDOUT: .C5 = %C5.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %B.decl: type = class_decl @B [template = constants.%B] {}
// CHECK:STDOUT: %C1.decl: type = class_decl @C1 [template = constants.%C1] {}
// CHECK:STDOUT: %C2.decl: type = class_decl @C2 [template = constants.%C2] {}
// CHECK:STDOUT: %C3.decl: type = class_decl @C3 [template = constants.%C3] {}
// CHECK:STDOUT: %C4.decl: type = class_decl @C4 [template = constants.%C4] {}
// CHECK:STDOUT: %C5.decl: type = class_decl @C5 [template = constants.%C5] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @B {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%B
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C1 {
// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
// CHECK:STDOUT: adapt_decl B
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C1
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C2 {
// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
// CHECK:STDOUT: adapt_decl B
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C3 {
// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
// CHECK:STDOUT: adapt_decl B
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C3
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C4 {
// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
// CHECK:STDOUT: adapt_decl B
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C4
// CHECK:STDOUT: extend name_scope2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C5 {
// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B.decl [template = constants.%B]
// CHECK:STDOUT: adapt_decl B
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C5
// CHECK:STDOUT: extend name_scope2
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -0,0 +1,195 @@
// 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
//
// AUTOUPDATE
// --- fail_adapt_with_base.carbon
library "fail_adapt_with_base" api;
base class Base {}
class AdaptWithBase {
// CHECK:STDERR: fail_adapt_with_base.carbon:[[@LINE+3]]:3: ERROR: Adapter cannot have a base class.
// CHECK:STDERR: adapt i32;
// CHECK:STDERR: ^~~~~~~~~~
adapt i32;
// CHECK:STDERR: fail_adapt_with_base.carbon:[[@LINE+4]]:3: `base` declaration is here.
// CHECK:STDERR: extend base: Base;
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
extend base: Base;
}
// --- fail_adapt_with_fields.carbon
library "fail_adapt_with_fields" api;
class AdaptWithField {
// CHECK:STDERR: fail_adapt_with_fields.carbon:[[@LINE+3]]:3: ERROR: Adapter cannot have fields.
// CHECK:STDERR: adapt i32;
// CHECK:STDERR: ^~~~~~~~~~
adapt i32;
// CHECK:STDERR: fail_adapt_with_fields.carbon:[[@LINE+4]]:7: First field declaration is here.
// CHECK:STDERR: var n: i32;
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR:
var n: i32;
}
class AdaptWithFields {
// CHECK:STDERR: fail_adapt_with_fields.carbon:[[@LINE+3]]:3: ERROR: Adapter cannot have fields.
// CHECK:STDERR: adapt i32;
// CHECK:STDERR: ^~~~~~~~~~
adapt i32;
// CHECK:STDERR: fail_adapt_with_fields.carbon:[[@LINE+4]]:7: First field declaration is here.
// CHECK:STDERR: var a: i32;
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR:
var a: i32;
var b: i32;
var c: i32;
}
// --- fail_adapt_with_base_and_fields.carbon
library "fail_adapt_with_base_and_fields" api;
base class Base {}
class AdaptWithBaseAndFields {
extend base: Base;
var n: i32;
// CHECK:STDERR: fail_adapt_with_base_and_fields.carbon:[[@LINE+6]]:3: ERROR: Adapter cannot have a base class.
// CHECK:STDERR: adapt {};
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_adapt_with_base_and_fields.carbon:[[@LINE-5]]:3: `base` declaration is here.
// CHECK:STDERR: extend base: Base;
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
adapt {};
}
// CHECK:STDOUT: --- fail_adapt_with_base.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Base: type = class_type @Base [template]
// CHECK:STDOUT: %.1: type = struct_type {} [template]
// CHECK:STDOUT: %AdaptWithBase: type = class_type @AdaptWithBase [template]
// CHECK:STDOUT: %.2: type = tuple_type () [template]
// CHECK:STDOUT: %.3: type = ptr_type {} [template]
// CHECK:STDOUT: %.4: type = unbound_element_type AdaptWithBase, Base [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .Base = %Base.decl
// CHECK:STDOUT: .AdaptWithBase = %AdaptWithBase.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %Base.decl: type = class_decl @Base [template = constants.%Base] {}
// CHECK:STDOUT: %AdaptWithBase.decl: type = class_decl @AdaptWithBase [template = constants.%AdaptWithBase] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @Base {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%Base
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @AdaptWithBase {
// CHECK:STDOUT: adapt_decl i32
// CHECK:STDOUT: %Base.ref: type = name_ref Base, file.%Base.decl [template = constants.%Base]
// CHECK:STDOUT: %.loc15: <unbound element of class AdaptWithBase> = base_decl Base, element0 [template]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%AdaptWithBase
// CHECK:STDOUT: .base = %.loc15
// CHECK:STDOUT: extend name_scope2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_adapt_with_fields.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %AdaptWithField: type = class_type @AdaptWithField [template]
// CHECK:STDOUT: %.1: type = unbound_element_type AdaptWithField, i32 [template]
// CHECK:STDOUT: %AdaptWithFields: type = class_type @AdaptWithFields [template]
// CHECK:STDOUT: %.2: type = unbound_element_type AdaptWithFields, i32 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .AdaptWithField = %AdaptWithField.decl
// CHECK:STDOUT: .AdaptWithFields = %AdaptWithFields.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %AdaptWithField.decl: type = class_decl @AdaptWithField [template = constants.%AdaptWithField] {}
// CHECK:STDOUT: %AdaptWithFields.decl: type = class_decl @AdaptWithFields [template = constants.%AdaptWithFields] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @AdaptWithField {
// CHECK:STDOUT: adapt_decl i32
// CHECK:STDOUT: %.loc13: <unbound element of class AdaptWithField> = field_decl n, element0 [template]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%AdaptWithField
// CHECK:STDOUT: .n = %.loc13
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @AdaptWithFields {
// CHECK:STDOUT: adapt_decl i32
// CHECK:STDOUT: %.loc25: <unbound element of class AdaptWithFields> = field_decl a, element0 [template]
// CHECK:STDOUT: %.loc26: <unbound element of class AdaptWithFields> = field_decl b, element1 [template]
// CHECK:STDOUT: %.loc27: <unbound element of class AdaptWithFields> = field_decl c, element2 [template]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%AdaptWithFields
// CHECK:STDOUT: .a = %.loc25
// CHECK:STDOUT: .b = %.loc26
// CHECK:STDOUT: .c = %.loc27
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_adapt_with_base_and_fields.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Base: type = class_type @Base [template]
// CHECK:STDOUT: %.1: type = struct_type {} [template]
// CHECK:STDOUT: %AdaptWithBaseAndFields: type = class_type @AdaptWithBaseAndFields [template]
// CHECK:STDOUT: %.2: type = tuple_type () [template]
// CHECK:STDOUT: %.3: type = ptr_type {} [template]
// CHECK:STDOUT: %.4: type = unbound_element_type AdaptWithBaseAndFields, Base [template]
// CHECK:STDOUT: %.5: type = unbound_element_type AdaptWithBaseAndFields, i32 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .Base = %Base.decl
// CHECK:STDOUT: .AdaptWithBaseAndFields = %AdaptWithBaseAndFields.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %Base.decl: type = class_decl @Base [template = constants.%Base] {}
// CHECK:STDOUT: %AdaptWithBaseAndFields.decl: type = class_decl @AdaptWithBaseAndFields [template = constants.%AdaptWithBaseAndFields] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @Base {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%Base
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @AdaptWithBaseAndFields {
// CHECK:STDOUT: %Base.ref: type = name_ref Base, file.%Base.decl [template = constants.%Base]
// CHECK:STDOUT: %.loc7: <unbound element of class AdaptWithBaseAndFields> = base_decl Base, element0 [template]
// CHECK:STDOUT: %.loc8: <unbound element of class AdaptWithBaseAndFields> = field_decl n, element1 [template]
// CHECK:STDOUT: %.loc15_10.1: {} = struct_literal ()
// CHECK:STDOUT: %.loc15_10.2: type = converted %.loc15_10.1, constants.%.1 [template = constants.%.1]
// CHECK:STDOUT: adapt_decl {}
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%AdaptWithBaseAndFields
// CHECK:STDOUT: .base = %.loc7
// CHECK:STDOUT: .n = %.loc8
// CHECK:STDOUT: extend name_scope2
// CHECK:STDOUT: }
// CHECK:STDOUT:
+295
View File
@@ -0,0 +1,295 @@
// 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
//
// AUTOUPDATE
// --- fail_todo_init_adapt.carbon
library "fail_todo_init_adapt" api;
class C {
var a: i32;
var b: i32;
}
class AdaptC {
adapt C;
}
let a: C = {.a = 1, .b = 2};
// TODO: Allow these as explicit conversions.
// CHECK:STDERR: fail_todo_init_adapt.carbon:[[@LINE+4]]:17: ERROR: Cannot convert from `C` to `AdaptC` with `as`.
// CHECK:STDERR: let b: AdaptC = a as AdaptC;
// CHECK:STDERR: ^~~~~~~~~~~
// CHECK:STDERR:
let b: AdaptC = a as AdaptC;
// CHECK:STDERR: fail_todo_init_adapt.carbon:[[@LINE+4]]:12: ERROR: Cannot convert from `AdaptC` to `C` with `as`.
// CHECK:STDERR: let c: C = b as C;
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR:
let c: C = b as C;
fn MakeC() -> C;
fn MakeAdaptC() -> AdaptC;
// CHECK:STDERR: fail_todo_init_adapt.carbon:[[@LINE+4]]:17: ERROR: Cannot convert from `C` to `AdaptC` with `as`.
// CHECK:STDERR: var d: AdaptC = MakeC() as AdaptC;
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
// CHECK:STDERR:
var d: AdaptC = MakeC() as AdaptC;
// CHECK:STDERR: fail_todo_init_adapt.carbon:[[@LINE+4]]:12: ERROR: Cannot convert from `AdaptC` to `C` with `as`.
// CHECK:STDERR: var e: C = MakeAdaptC() as C;
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
// CHECK:STDERR:
var e: C = MakeAdaptC() as C;
// --- fail_not_implicit.carbon
library "fail_not_implicit" api;
class C {
var a: i32;
var b: i32;
}
class AdaptC {
adapt C;
}
let a: C = {.a = 1, .b = 2};
// Cannot implicitly convert between a type and an adapter for the type.
// CHECK:STDERR: fail_not_implicit.carbon:[[@LINE+4]]:1: ERROR: Cannot implicitly convert from `C` to `AdaptC`.
// CHECK:STDERR: let b: AdaptC = a;
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
let b: AdaptC = a;
// CHECK:STDERR: fail_not_implicit.carbon:[[@LINE+4]]:1: ERROR: Cannot implicitly convert from `AdaptC` to `C`.
// CHECK:STDERR: let c: C = b;
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
let c: C = b;
fn MakeC() -> C;
fn MakeAdaptC() -> AdaptC;
// CHECK:STDERR: fail_not_implicit.carbon:[[@LINE+4]]:1: ERROR: Cannot implicitly convert from `C` to `AdaptC`.
// CHECK:STDERR: var d: AdaptC = MakeC();
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
var d: AdaptC = MakeC();
// CHECK:STDERR: fail_not_implicit.carbon:[[@LINE+3]]:1: ERROR: Cannot implicitly convert from `AdaptC` to `C`.
// CHECK:STDERR: var e: C = MakeAdaptC();
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~
var e: C = MakeAdaptC();
// CHECK:STDOUT: --- fail_todo_init_adapt.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.1: type = unbound_element_type C, i32 [template]
// CHECK:STDOUT: %.2: type = struct_type {.a: i32, .b: i32} [template]
// CHECK:STDOUT: %AdaptC: type = class_type @AdaptC [template]
// CHECK:STDOUT: %.3: type = ptr_type {.a: i32, .b: i32} [template]
// CHECK:STDOUT: %.4: i32 = int_literal 1 [template]
// CHECK:STDOUT: %.5: i32 = int_literal 2 [template]
// CHECK:STDOUT: %.6: C = struct_value (%.4, %.5) [template]
// CHECK:STDOUT: %.7: type = ptr_type C [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .C = %C.decl
// CHECK:STDOUT: .AdaptC = %AdaptC.decl
// CHECK:STDOUT: .MakeC = %MakeC
// CHECK:STDOUT: .MakeAdaptC = %MakeAdaptC
// CHECK:STDOUT: .d = %d
// CHECK:STDOUT: .e = %e
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %AdaptC.decl: type = class_decl @AdaptC [template = constants.%AdaptC] {}
// CHECK:STDOUT: %C.ref.loc13: type = name_ref C, %C.decl [template = constants.%C]
// CHECK:STDOUT: %.loc13_18: i32 = int_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %.loc13_26: i32 = int_literal 2 [template = constants.%.5]
// CHECK:STDOUT: %.loc13_27.1: {.a: i32, .b: i32} = struct_literal (%.loc13_18, %.loc13_26)
// CHECK:STDOUT: %.loc13_27.2: ref C = temporary_storage
// CHECK:STDOUT: %.loc13_27.3: ref i32 = class_element_access %.loc13_27.2, element0
// CHECK:STDOUT: %.loc13_27.4: init i32 = initialize_from %.loc13_18 to %.loc13_27.3 [template = constants.%.4]
// CHECK:STDOUT: %.loc13_27.5: ref i32 = class_element_access %.loc13_27.2, element1
// CHECK:STDOUT: %.loc13_27.6: init i32 = initialize_from %.loc13_26 to %.loc13_27.5 [template = constants.%.5]
// CHECK:STDOUT: %.loc13_27.7: init C = class_init (%.loc13_27.4, %.loc13_27.6), %.loc13_27.2 [template = constants.%.6]
// CHECK:STDOUT: %.loc13_27.8: ref C = temporary %.loc13_27.2, %.loc13_27.7
// CHECK:STDOUT: %.loc13_27.9: ref C = converted %.loc13_27.1, %.loc13_27.8
// CHECK:STDOUT: %.loc13_27.10: C = bind_value %.loc13_27.9
// CHECK:STDOUT: %a: C = bind_name a, %.loc13_27.10
// CHECK:STDOUT: %AdaptC.ref.loc21_8: type = name_ref AdaptC, %AdaptC.decl [template = constants.%AdaptC]
// CHECK:STDOUT: %a.ref: C = name_ref a, %a
// CHECK:STDOUT: %AdaptC.ref.loc21_22: type = name_ref AdaptC, %AdaptC.decl [template = constants.%AdaptC]
// CHECK:STDOUT: %b: AdaptC = bind_name b, <error>
// CHECK:STDOUT: %C.ref.loc27_8: type = name_ref C, %C.decl [template = constants.%C]
// CHECK:STDOUT: %b.ref: AdaptC = name_ref b, %b
// CHECK:STDOUT: %C.ref.loc27_17: type = name_ref C, %C.decl [template = constants.%C]
// CHECK:STDOUT: %c: C = bind_name c, <error>
// CHECK:STDOUT: %MakeC: <function> = fn_decl @MakeC [template] {
// CHECK:STDOUT: %C.ref.loc29: type = name_ref C, %C.decl [template = constants.%C]
// CHECK:STDOUT: @MakeC.%return: ref C = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %MakeAdaptC: <function> = fn_decl @MakeAdaptC [template] {
// CHECK:STDOUT: %AdaptC.ref.loc31: type = name_ref AdaptC, %AdaptC.decl [template = constants.%AdaptC]
// CHECK:STDOUT: @MakeAdaptC.%return: ref AdaptC = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %AdaptC.ref.loc37: type = name_ref AdaptC, %AdaptC.decl [template = constants.%AdaptC]
// CHECK:STDOUT: %d.var: ref AdaptC = var d
// CHECK:STDOUT: %d: ref AdaptC = bind_name d, %d.var
// CHECK:STDOUT: %C.ref.loc43: type = name_ref C, %C.decl [template = constants.%C]
// CHECK:STDOUT: %e.var: ref C = var e
// CHECK:STDOUT: %e: ref C = bind_name e, %e.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: %.loc5: <unbound element of class C> = field_decl a, element0 [template]
// CHECK:STDOUT: %.loc6: <unbound element of class C> = field_decl b, element1 [template]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: .a = %.loc5
// CHECK:STDOUT: .b = %.loc6
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @AdaptC {
// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [template = constants.%C]
// CHECK:STDOUT: adapt_decl C
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%AdaptC
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @MakeC() -> %return: C;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @MakeAdaptC() -> %return: AdaptC;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %MakeC.ref: <function> = name_ref MakeC, file.%MakeC [template = file.%MakeC]
// CHECK:STDOUT: %.loc37_22.1: ref C = temporary_storage
// CHECK:STDOUT: %.loc37_22.2: init C = call %MakeC.ref() to %.loc37_22.1
// CHECK:STDOUT: %AdaptC.ref: type = name_ref AdaptC, file.%AdaptC.decl [template = constants.%AdaptC]
// CHECK:STDOUT: assign file.%d.var, <error>
// CHECK:STDOUT: %MakeAdaptC.ref: <function> = name_ref MakeAdaptC, file.%MakeAdaptC [template = file.%MakeAdaptC]
// CHECK:STDOUT: %.loc43_22.1: ref AdaptC = temporary_storage
// CHECK:STDOUT: %.loc43_22.2: init AdaptC = call %MakeAdaptC.ref() to %.loc43_22.1
// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [template = constants.%C]
// CHECK:STDOUT: assign file.%e.var, <error>
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_not_implicit.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.1: type = unbound_element_type C, i32 [template]
// CHECK:STDOUT: %.2: type = struct_type {.a: i32, .b: i32} [template]
// CHECK:STDOUT: %AdaptC: type = class_type @AdaptC [template]
// CHECK:STDOUT: %.3: type = ptr_type {.a: i32, .b: i32} [template]
// CHECK:STDOUT: %.4: i32 = int_literal 1 [template]
// CHECK:STDOUT: %.5: i32 = int_literal 2 [template]
// CHECK:STDOUT: %.6: C = struct_value (%.4, %.5) [template]
// CHECK:STDOUT: %.7: type = ptr_type C [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .C = %C.decl
// CHECK:STDOUT: .AdaptC = %AdaptC.decl
// CHECK:STDOUT: .MakeC = %MakeC
// CHECK:STDOUT: .MakeAdaptC = %MakeAdaptC
// CHECK:STDOUT: .d = %d
// CHECK:STDOUT: .e = %e
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %AdaptC.decl: type = class_decl @AdaptC [template = constants.%AdaptC] {}
// CHECK:STDOUT: %C.ref.loc13: type = name_ref C, %C.decl [template = constants.%C]
// CHECK:STDOUT: %.loc13_18: i32 = int_literal 1 [template = constants.%.4]
// CHECK:STDOUT: %.loc13_26: i32 = int_literal 2 [template = constants.%.5]
// CHECK:STDOUT: %.loc13_27.1: {.a: i32, .b: i32} = struct_literal (%.loc13_18, %.loc13_26)
// CHECK:STDOUT: %.loc13_27.2: ref C = temporary_storage
// CHECK:STDOUT: %.loc13_27.3: ref i32 = class_element_access %.loc13_27.2, element0
// CHECK:STDOUT: %.loc13_27.4: init i32 = initialize_from %.loc13_18 to %.loc13_27.3 [template = constants.%.4]
// CHECK:STDOUT: %.loc13_27.5: ref i32 = class_element_access %.loc13_27.2, element1
// CHECK:STDOUT: %.loc13_27.6: init i32 = initialize_from %.loc13_26 to %.loc13_27.5 [template = constants.%.5]
// CHECK:STDOUT: %.loc13_27.7: init C = class_init (%.loc13_27.4, %.loc13_27.6), %.loc13_27.2 [template = constants.%.6]
// CHECK:STDOUT: %.loc13_27.8: ref C = temporary %.loc13_27.2, %.loc13_27.7
// CHECK:STDOUT: %.loc13_27.9: ref C = converted %.loc13_27.1, %.loc13_27.8
// CHECK:STDOUT: %.loc13_27.10: C = bind_value %.loc13_27.9
// CHECK:STDOUT: %a: C = bind_name a, %.loc13_27.10
// CHECK:STDOUT: %AdaptC.ref.loc21: type = name_ref AdaptC, %AdaptC.decl [template = constants.%AdaptC]
// CHECK:STDOUT: %a.ref: C = name_ref a, %a
// CHECK:STDOUT: %b: AdaptC = bind_name b, <error>
// CHECK:STDOUT: %C.ref.loc27: type = name_ref C, %C.decl [template = constants.%C]
// CHECK:STDOUT: %b.ref: AdaptC = name_ref b, %b
// CHECK:STDOUT: %c: C = bind_name c, <error>
// CHECK:STDOUT: %MakeC: <function> = fn_decl @MakeC [template] {
// CHECK:STDOUT: %C.ref.loc29: type = name_ref C, %C.decl [template = constants.%C]
// CHECK:STDOUT: @MakeC.%return: ref C = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %MakeAdaptC: <function> = fn_decl @MakeAdaptC [template] {
// CHECK:STDOUT: %AdaptC.ref.loc31: type = name_ref AdaptC, %AdaptC.decl [template = constants.%AdaptC]
// CHECK:STDOUT: @MakeAdaptC.%return: ref AdaptC = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %AdaptC.ref.loc37: type = name_ref AdaptC, %AdaptC.decl [template = constants.%AdaptC]
// CHECK:STDOUT: %d.var: ref AdaptC = var d
// CHECK:STDOUT: %d: ref AdaptC = bind_name d, %d.var
// CHECK:STDOUT: %C.ref.loc42: type = name_ref C, %C.decl [template = constants.%C]
// CHECK:STDOUT: %e.var: ref C = var e
// CHECK:STDOUT: %e: ref C = bind_name e, %e.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: %.loc5: <unbound element of class C> = field_decl a, element0 [template]
// CHECK:STDOUT: %.loc6: <unbound element of class C> = field_decl b, element1 [template]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: .a = %.loc5
// CHECK:STDOUT: .b = %.loc6
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @AdaptC {
// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [template = constants.%C]
// CHECK:STDOUT: adapt_decl C
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%AdaptC
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @MakeC() -> %return: C;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @MakeAdaptC() -> %return: AdaptC;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %MakeC.ref: <function> = name_ref MakeC, file.%MakeC [template = file.%MakeC]
// CHECK:STDOUT: %.loc37_22.1: ref C = temporary_storage
// CHECK:STDOUT: %.loc37_22.2: init C = call %MakeC.ref() to %.loc37_22.1
// CHECK:STDOUT: assign file.%d.var, <error>
// CHECK:STDOUT: %MakeAdaptC.ref: <function> = name_ref MakeAdaptC, file.%MakeAdaptC [template = file.%MakeAdaptC]
// CHECK:STDOUT: %.loc42_22.1: ref AdaptC = temporary_storage
// CHECK:STDOUT: %.loc42_22.2: init AdaptC = call %MakeAdaptC.ref() to %.loc42_22.1
// CHECK:STDOUT: assign file.%e.var, <error>
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
+8 -3
View File
@@ -183,16 +183,20 @@ CARBON_DIAGNOSTIC_KIND(InvalidBuiltinSignature)
CARBON_DIAGNOSTIC_KIND(FunctionExternMismatch)
// Class checking.
CARBON_DIAGNOSTIC_KIND(AdaptWithBase)
CARBON_DIAGNOSTIC_KIND(AdaptWithFields)
CARBON_DIAGNOSTIC_KIND(AdaptBaseHere)
CARBON_DIAGNOSTIC_KIND(AdaptFieldHere)
CARBON_DIAGNOSTIC_KIND(BaseIsFinal)
CARBON_DIAGNOSTIC_KIND(BaseMissingExtend)
CARBON_DIAGNOSTIC_KIND(BaseOutsideClass)
CARBON_DIAGNOSTIC_KIND(BasePrevious)
CARBON_DIAGNOSTIC_KIND(BaseRepeated)
CARBON_DIAGNOSTIC_KIND(ClassForwardDeclaredHere)
CARBON_DIAGNOSTIC_KIND(ClassPreviousDefinition)
CARBON_DIAGNOSTIC_KIND(ClassRedeclarationDifferentIntroducer)
CARBON_DIAGNOSTIC_KIND(ClassRedeclarationDifferentIntroducerPrevious)
CARBON_DIAGNOSTIC_KIND(ClassRedefinition)
CARBON_DIAGNOSTIC_KIND(ClassSpecificDeclOutsideClass)
CARBON_DIAGNOSTIC_KIND(ClassSpecificDeclPrevious)
CARBON_DIAGNOSTIC_KIND(ClassSpecificDeclRepeated)
CARBON_DIAGNOSTIC_KIND(ClassIncompleteWithinDefinition)
CARBON_DIAGNOSTIC_KIND(ConstructionOfAbstractClass)
@@ -260,6 +264,7 @@ CARBON_DIAGNOSTIC_KIND(NameNotFound)
CARBON_DIAGNOSTIC_KIND(NameDeclDuplicate)
CARBON_DIAGNOSTIC_KIND(NameDeclPrevious)
CARBON_DIAGNOSTIC_KIND(RepeatedConst)
CARBON_DIAGNOSTIC_KIND(IncompleteTypeInAdaptDecl)
CARBON_DIAGNOSTIC_KIND(IncompleteTypeInBaseDecl)
CARBON_DIAGNOSTIC_KIND(IncompleteTypeInConversion)
CARBON_DIAGNOSTIC_KIND(IncompleteTypeInFunctionParam)
+5
View File
@@ -26,6 +26,11 @@ static auto FatalErrorIfEncountered(InstT inst) -> void {
<< inst;
}
auto HandleAdaptDecl(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/,
SemIR::AdaptDecl inst) -> void {
FatalErrorIfEncountered(inst);
}
auto HandleAddrOf(FunctionContext& context, SemIR::InstId inst_id,
SemIR::AddrOf inst) -> void {
context.SetLocal(inst_id, context.GetValue(inst.lvalue_id));
+26
View File
@@ -0,0 +1,26 @@
// 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
//
// AUTOUPDATE
class PairOfInts {
var a: i32;
var b: i32;
}
class PairAdapter {
adapt PairOfInts;
}
fn MakePair() -> PairAdapter {
returned var v: PairAdapter;
return var;
}
// CHECK:STDOUT: ; ModuleID = 'adapt.carbon'
// CHECK:STDOUT: source_filename = "adapt.carbon"
// CHECK:STDOUT:
// CHECK:STDOUT: define void @MakePair(ptr sret({ i32, i32 }) %return) {
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
+41 -8
View File
@@ -4,26 +4,59 @@
//
// AUTOUPDATE
virtual class B
// --- fail_virtual_class.carbon
// CHECK:STDERR: fail_modifiers.carbon:[[@LINE+7]]:1: ERROR: `virtual` declarations must either end with a `;` or have a `{ ... }` block for a definition.
virtual class B
// CHECK:STDERR: fail_virtual_class.carbon:[[@LINE+4]]:1: ERROR: `virtual` declarations must either end with a `;` or have a `{ ... }` block for a definition.
// CHECK:STDERR:
// CHECK:STDERR: ^
// CHECK:STDERR:
// --- fail_impl_class.carbon
// CHECK:STDERR: fail_impl_class.carbon:[[@LINE+4]]:1: ERROR: `impl` introducer should be followed by a name.
// CHECK:STDERR: impl class
// CHECK:STDERR: ^~~~
// CHECK:STDERR:
// CHECK:STDERR: fail_modifiers.carbon:[[@LINE+3]]:6: ERROR: `class` introducer should be followed by a name.
// CHECK:STDERR: impl class
// CHECK:STDERR: ^~~~~
impl class
// CHECK:STDOUT: - filename: fail_modifiers.carbon
// --- fail_extend_adapt_base.carbon
class C {
// CHECK:STDERR: fail_extend_adapt_base.carbon:[[@LINE+3]]:16: ERROR: Expected expression.
// CHECK:STDERR: extend adapt base B;
// CHECK:STDERR: ^~~~
extend adapt base B;
}
// CHECK:STDOUT: - filename: fail_virtual_class.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'},
// CHECK:STDOUT: {kind: 'VirtualModifier', text: 'virtual'},
// CHECK:STDOUT: {kind: 'IdentifierName', text: 'B'},
// CHECK:STDOUT: {kind: 'ClassDecl', text: 'impl', has_error: yes, subtree_size: 4},
// CHECK:STDOUT: {kind: 'ClassDecl', text: 'B', has_error: yes, subtree_size: 4},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: fail_impl_class.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'},
// CHECK:STDOUT: {kind: 'ImplModifier', text: 'impl'},
// CHECK:STDOUT: {kind: 'InvalidParse', text: '', has_error: yes},
// CHECK:STDOUT: {kind: 'ClassDecl', text: 'class', has_error: yes, subtree_size: 3},
// CHECK:STDOUT: {kind: 'ClassDecl', text: 'class', has_error: yes, subtree_size: 4},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDOUT: - filename: fail_extend_adapt_base.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'},
// CHECK:STDOUT: {kind: 'IdentifierName', text: 'C'},
// CHECK:STDOUT: {kind: 'ClassDefinitionStart', text: '{', subtree_size: 3},
// CHECK:STDOUT: {kind: 'AdaptIntroducer', text: 'adapt'},
// CHECK:STDOUT: {kind: 'ExtendModifier', text: 'extend'},
// CHECK:STDOUT: {kind: 'InvalidParse', text: 'base', has_error: yes},
// CHECK:STDOUT: {kind: 'AdaptDecl', text: ';', has_error: yes, subtree_size: 4},
// CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 8},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
+5
View File
@@ -56,6 +56,11 @@ struct Class : public Printable<Class> {
// The following members are accumulated throughout the class definition.
// The adapted type declaration, if any. Invalid if the class is not an
// adapter. This is an AdaptDecl instruction.
// TODO: Consider sharing the storage for `adapt_id` and `base_id`. A class
// can't have both.
InstId adapt_id = InstId::Invalid;
// The base class declaration. Invalid if the class has no base class. This is
// a BaseDecl instruction.
InstId base_id = InstId::Invalid;
+3
View File
@@ -221,6 +221,7 @@ static auto GetTypePrecedence(InstKind kind) -> int {
case PointerType::Kind:
return -2;
case AdaptDecl::Kind:
case AddrOf::Kind:
case AddrPattern::Kind:
case ArrayIndex::Kind:
@@ -477,6 +478,7 @@ static auto StringifyTypeExprImpl(const SemIR::File& outer_sem_ir,
}
break;
}
case AdaptDecl::Kind:
case AddrOf::Kind:
case AddrPattern::Kind:
case ArrayIndex::Kind:
@@ -560,6 +562,7 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory {
while (true) {
auto untyped_inst = ir->insts().Get(inst_id);
CARBON_KIND_SWITCH(untyped_inst) {
case AdaptDecl::Kind:
case Assign::Kind:
case BaseDecl::Kind:
case Branch::Kind:
+1
View File
@@ -17,6 +17,7 @@
// For each instruction kind declared here there is a matching definition in
// `typed_insts.h`.
CARBON_SEM_IR_INST_KIND(AdaptDecl)
CARBON_SEM_IR_INST_KIND(AddrOf)
CARBON_SEM_IR_INST_KIND(AddrPattern)
CARBON_SEM_IR_INST_KIND(ArrayIndex)
+9
View File
@@ -44,6 +44,15 @@
namespace Carbon::SemIR {
// An adapted type declaration in a class, of the form `adapt T;`.
struct AdaptDecl {
static constexpr auto Kind =
InstKind::AdaptDecl.Define<Parse::AdaptDeclId>("adapt_decl");
// No type_id; this is not a value.
TypeId adapted_type_id;
};
struct AddrOf {
// TODO: Make Parse::NodeId more specific.
static constexpr auto Kind =