Skip to content

Commit 1331ade

Browse files
authored
Attempt to complete the source type in a conversion. (#5984)
This is necessary if the source type is an adapter, as we would not otherwise be able to determine what type it adapts and hence could be converted to.
1 parent 8c90808 commit 1331ade

15 files changed

+300
-195
lines changed

toolchain/check/convert.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,14 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
13031303
return SemIR::ErrorInst::InstId;
13041304
}
13051305

1306+
// The source type doesn't need to be complete, but its completeness can
1307+
// affect the result. For example, we don't know what type it adapts or
1308+
// derives from unless it's complete.
1309+
// TODO: Is there a risk of coherence problems if the source type is
1310+
// incomplete, but a conversion would have been possible or would have behaved
1311+
// differently if it were complete?
1312+
TryToCompleteType(context, context.insts().Get(expr_id).type_id(), loc_id);
1313+
13061314
// Check whether any builtin conversion applies.
13071315
expr_id = PerformBuiltinConversion(context, loc_id, expr_id, target,
13081316
vtable_class_type);

toolchain/check/testdata/as/basics.carbon

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ let n: {.x: ()} = {.x = ()} as {.x = ()};
175175
// CHECK:STDOUT: constants {
176176
// CHECK:STDOUT: %pattern_type: type = pattern_type type [concrete]
177177
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
178-
// CHECK:STDOUT: %tuple.type: type = tuple_type (%empty_struct_type, %empty_struct_type) [concrete]
178+
// CHECK:STDOUT: %tuple.type.b6b: type = tuple_type (%empty_struct_type, %empty_struct_type) [concrete]
179179
// CHECK:STDOUT: }
180180
// CHECK:STDOUT:
181181
// CHECK:STDOUT: imports {
@@ -192,10 +192,10 @@ let n: {.x: ()} = {.x = ()} as {.x = ()};
192192
// CHECK:STDOUT: !entry:
193193
// CHECK:STDOUT: %.loc5_17: %empty_struct_type = struct_literal ()
194194
// CHECK:STDOUT: %.loc5_21: %empty_struct_type = struct_literal ()
195-
// CHECK:STDOUT: %.loc5_22: %tuple.type = tuple_literal (%.loc5_17, %.loc5_21)
195+
// CHECK:STDOUT: %.loc5_22: %tuple.type.b6b = tuple_literal (%.loc5_17, %.loc5_21)
196196
// CHECK:STDOUT: %.loc5_24.1: type = converted %.loc5_17, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
197197
// CHECK:STDOUT: %.loc5_24.2: type = converted %.loc5_21, constants.%empty_struct_type [concrete = constants.%empty_struct_type]
198-
// CHECK:STDOUT: %.loc5_24.3: type = converted %.loc5_22, constants.%tuple.type [concrete = constants.%tuple.type]
198+
// CHECK:STDOUT: %.loc5_24.3: type = converted %.loc5_22, constants.%tuple.type.b6b [concrete = constants.%tuple.type.b6b]
199199
// CHECK:STDOUT: <elided>
200200
// CHECK:STDOUT: }
201201
// CHECK:STDOUT:

toolchain/check/testdata/basics/raw_sem_ir/one_file.carbon

Lines changed: 109 additions & 103 deletions
Large diffs are not rendered by default.

toolchain/check/testdata/basics/raw_sem_ir/one_file_with_textual_ir.carbon

Lines changed: 47 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ fn Foo(n: ()) -> ((), ()) {
2525
// CHECK:STDOUT: ir1: {decl_id: inst<none>, is_export: false}
2626
// CHECK:STDOUT: import_ir_insts: {}
2727
// CHECK:STDOUT: name_scopes:
28-
// CHECK:STDOUT: name_scope0: {inst: inst14, parent_scope: name_scope<none>, has_error: false, extended_scopes: [], names: {name0: inst36}}
28+
// CHECK:STDOUT: name_scope0: {inst: inst14, parent_scope: name_scope<none>, has_error: false, extended_scopes: [], names: {name0: inst37}}
2929
// CHECK:STDOUT: entity_names:
3030
// CHECK:STDOUT: entity_name0: {name: name1, parent_scope: name_scope<none>, index: -1, is_template: 0}
3131
// CHECK:STDOUT: functions:
32-
// CHECK:STDOUT: function0: {name: name0, parent_scope: name_scope0, call_params_id: inst_block9, return_slot_pattern: inst31, body: [inst_block12]}
32+
// CHECK:STDOUT: function0: {name: name0, parent_scope: name_scope0, call_params_id: inst_block9, return_slot_pattern: inst32, body: [inst_block12]}
3333
// CHECK:STDOUT: classes: {}
3434
// CHECK:STDOUT: generics: {}
3535
// CHECK:STDOUT: specifics: {}
@@ -42,55 +42,55 @@ fn Foo(n: ()) -> ((), ()) {
4242
// CHECK:STDOUT: value_repr: {kind: copy, type: type(Error)}
4343
// CHECK:STDOUT: 'type(inst(NamespaceType))':
4444
// CHECK:STDOUT: value_repr: {kind: copy, type: type(inst(NamespaceType))}
45-
// CHECK:STDOUT: 'type(inst37)':
46-
// CHECK:STDOUT: value_repr: {kind: none, type: type(inst15)}
4745
// CHECK:STDOUT: 'type(inst15)':
4846
// CHECK:STDOUT: value_repr: {kind: none, type: type(inst15)}
4947
// CHECK:STDOUT: 'type(inst24)':
50-
// CHECK:STDOUT: value_repr: {kind: pointer, type: type(inst39)}
51-
// CHECK:STDOUT: 'type(inst39)':
52-
// CHECK:STDOUT: value_repr: {kind: copy, type: type(inst39)}
48+
// CHECK:STDOUT: value_repr: {kind: pointer, type: type(inst26)}
49+
// CHECK:STDOUT: 'type(inst26)':
50+
// CHECK:STDOUT: value_repr: {kind: copy, type: type(inst26)}
51+
// CHECK:STDOUT: 'type(inst38)':
52+
// CHECK:STDOUT: value_repr: {kind: none, type: type(inst15)}
5353
// CHECK:STDOUT: insts:
5454
// CHECK:STDOUT: inst14: {kind: Namespace, arg0: name_scope0, arg1: inst<none>, type: type(inst(NamespaceType))}
5555
// CHECK:STDOUT: inst15: {kind: TupleType, arg0: inst_block_empty, type: type(TypeType)}
5656
// CHECK:STDOUT: inst16: {kind: TupleLiteral, arg0: inst_block_empty, type: type(inst15)}
5757
// CHECK:STDOUT: inst17: {kind: Converted, arg0: inst16, arg1: inst15, type: type(TypeType)}
58-
// CHECK:STDOUT: inst18: {kind: BindName, arg0: entity_name0, arg1: inst32, type: type(inst15)}
58+
// CHECK:STDOUT: inst18: {kind: BindName, arg0: entity_name0, arg1: inst33, type: type(inst15)}
5959
// CHECK:STDOUT: inst19: {kind: PatternType, arg0: inst15, type: type(TypeType)}
6060
// CHECK:STDOUT: inst20: {kind: BindingPattern, arg0: entity_name0, type: type(inst19)}
6161
// CHECK:STDOUT: inst21: {kind: ValueParamPattern, arg0: inst20, arg1: call_param0, type: type(inst19)}
6262
// CHECK:STDOUT: inst22: {kind: TupleLiteral, arg0: inst_block_empty, type: type(inst15)}
6363
// CHECK:STDOUT: inst23: {kind: TupleLiteral, arg0: inst_block_empty, type: type(inst15)}
6464
// CHECK:STDOUT: inst24: {kind: TupleType, arg0: inst_block7, type: type(TypeType)}
6565
// CHECK:STDOUT: inst25: {kind: TupleLiteral, arg0: inst_block6, type: type(inst24)}
66-
// CHECK:STDOUT: inst26: {kind: Converted, arg0: inst22, arg1: inst15, type: type(TypeType)}
67-
// CHECK:STDOUT: inst27: {kind: Converted, arg0: inst23, arg1: inst15, type: type(TypeType)}
68-
// CHECK:STDOUT: inst28: {kind: Converted, arg0: inst25, arg1: inst24, type: type(TypeType)}
69-
// CHECK:STDOUT: inst29: {kind: PatternType, arg0: inst24, type: type(TypeType)}
70-
// CHECK:STDOUT: inst30: {kind: ReturnSlotPattern, arg0: inst28, type: type(inst29)}
71-
// CHECK:STDOUT: inst31: {kind: OutParamPattern, arg0: inst30, arg1: call_param1, type: type(inst29)}
72-
// CHECK:STDOUT: inst32: {kind: ValueParam, arg0: call_param0, arg1: name1, type: type(inst15)}
73-
// CHECK:STDOUT: inst33: {kind: SpliceBlock, arg0: inst_block4, arg1: inst17, type: type(TypeType)}
74-
// CHECK:STDOUT: inst34: {kind: OutParam, arg0: call_param1, arg1: name(ReturnSlot), type: type(inst24)}
75-
// CHECK:STDOUT: inst35: {kind: ReturnSlot, arg0: inst24, arg1: inst34, type: type(inst24)}
76-
// CHECK:STDOUT: inst36: {kind: FunctionDecl, arg0: function0, arg1: inst_block11, type: type(inst37)}
77-
// CHECK:STDOUT: inst37: {kind: FunctionType, arg0: function0, arg1: specific<none>, type: type(TypeType)}
78-
// CHECK:STDOUT: inst38: {kind: StructValue, arg0: inst_block_empty, type: type(inst37)}
79-
// CHECK:STDOUT: inst39: {kind: PointerType, arg0: inst24, type: type(TypeType)}
66+
// CHECK:STDOUT: inst26: {kind: PointerType, arg0: inst24, type: type(TypeType)}
67+
// CHECK:STDOUT: inst27: {kind: Converted, arg0: inst22, arg1: inst15, type: type(TypeType)}
68+
// CHECK:STDOUT: inst28: {kind: Converted, arg0: inst23, arg1: inst15, type: type(TypeType)}
69+
// CHECK:STDOUT: inst29: {kind: Converted, arg0: inst25, arg1: inst24, type: type(TypeType)}
70+
// CHECK:STDOUT: inst30: {kind: PatternType, arg0: inst24, type: type(TypeType)}
71+
// CHECK:STDOUT: inst31: {kind: ReturnSlotPattern, arg0: inst29, type: type(inst30)}
72+
// CHECK:STDOUT: inst32: {kind: OutParamPattern, arg0: inst31, arg1: call_param1, type: type(inst30)}
73+
// CHECK:STDOUT: inst33: {kind: ValueParam, arg0: call_param0, arg1: name1, type: type(inst15)}
74+
// CHECK:STDOUT: inst34: {kind: SpliceBlock, arg0: inst_block4, arg1: inst17, type: type(TypeType)}
75+
// CHECK:STDOUT: inst35: {kind: OutParam, arg0: call_param1, arg1: name(ReturnSlot), type: type(inst24)}
76+
// CHECK:STDOUT: inst36: {kind: ReturnSlot, arg0: inst24, arg1: inst35, type: type(inst24)}
77+
// CHECK:STDOUT: inst37: {kind: FunctionDecl, arg0: function0, arg1: inst_block11, type: type(inst38)}
78+
// CHECK:STDOUT: inst38: {kind: FunctionType, arg0: function0, arg1: specific<none>, type: type(TypeType)}
79+
// CHECK:STDOUT: inst39: {kind: StructValue, arg0: inst_block_empty, type: type(inst38)}
8080
// CHECK:STDOUT: inst40: {kind: NameRef, arg0: name1, arg1: inst18, type: type(inst15)}
8181
// CHECK:STDOUT: inst41: {kind: TupleLiteral, arg0: inst_block_empty, type: type(inst15)}
8282
// CHECK:STDOUT: inst42: {kind: TupleLiteral, arg0: inst_block13, type: type(inst24)}
83-
// CHECK:STDOUT: inst43: {kind: TupleAccess, arg0: inst35, arg1: element0, type: type(inst15)}
83+
// CHECK:STDOUT: inst43: {kind: TupleAccess, arg0: inst36, arg1: element0, type: type(inst15)}
8484
// CHECK:STDOUT: inst44: {kind: TupleInit, arg0: inst_block14, arg1: inst43, type: type(inst15)}
8585
// CHECK:STDOUT: inst45: {kind: TupleValue, arg0: inst_block_empty, type: type(inst15)}
8686
// CHECK:STDOUT: inst46: {kind: Converted, arg0: inst40, arg1: inst44, type: type(inst15)}
87-
// CHECK:STDOUT: inst47: {kind: TupleAccess, arg0: inst35, arg1: element1, type: type(inst15)}
87+
// CHECK:STDOUT: inst47: {kind: TupleAccess, arg0: inst36, arg1: element1, type: type(inst15)}
8888
// CHECK:STDOUT: inst48: {kind: TupleInit, arg0: inst_block_empty, arg1: inst47, type: type(inst15)}
8989
// CHECK:STDOUT: inst49: {kind: Converted, arg0: inst41, arg1: inst48, type: type(inst15)}
90-
// CHECK:STDOUT: inst50: {kind: TupleInit, arg0: inst_block15, arg1: inst35, type: type(inst24)}
90+
// CHECK:STDOUT: inst50: {kind: TupleInit, arg0: inst_block15, arg1: inst36, type: type(inst24)}
9191
// CHECK:STDOUT: inst51: {kind: TupleValue, arg0: inst_block16, type: type(inst24)}
9292
// CHECK:STDOUT: inst52: {kind: Converted, arg0: inst42, arg1: inst50, type: type(inst24)}
93-
// CHECK:STDOUT: inst53: {kind: ReturnExpr, arg0: inst52, arg1: inst35}
93+
// CHECK:STDOUT: inst53: {kind: ReturnExpr, arg0: inst52, arg1: inst36}
9494
// CHECK:STDOUT: constant_values:
9595
// CHECK:STDOUT: values:
9696
// CHECK:STDOUT: inst14: concrete_constant(inst14)
@@ -100,15 +100,15 @@ fn Foo(n: ()) -> ((), ()) {
100100
// CHECK:STDOUT: inst20: concrete_constant(inst20)
101101
// CHECK:STDOUT: inst21: concrete_constant(inst21)
102102
// CHECK:STDOUT: inst24: concrete_constant(inst24)
103-
// CHECK:STDOUT: inst26: concrete_constant(inst15)
103+
// CHECK:STDOUT: inst26: concrete_constant(inst26)
104104
// CHECK:STDOUT: inst27: concrete_constant(inst15)
105-
// CHECK:STDOUT: inst28: concrete_constant(inst24)
106-
// CHECK:STDOUT: inst29: concrete_constant(inst29)
105+
// CHECK:STDOUT: inst28: concrete_constant(inst15)
106+
// CHECK:STDOUT: inst29: concrete_constant(inst24)
107107
// CHECK:STDOUT: inst30: concrete_constant(inst30)
108108
// CHECK:STDOUT: inst31: concrete_constant(inst31)
109-
// CHECK:STDOUT: inst33: concrete_constant(inst15)
110-
// CHECK:STDOUT: inst36: concrete_constant(inst38)
111-
// CHECK:STDOUT: inst37: concrete_constant(inst37)
109+
// CHECK:STDOUT: inst32: concrete_constant(inst32)
110+
// CHECK:STDOUT: inst34: concrete_constant(inst15)
111+
// CHECK:STDOUT: inst37: concrete_constant(inst39)
112112
// CHECK:STDOUT: inst38: concrete_constant(inst38)
113113
// CHECK:STDOUT: inst39: concrete_constant(inst39)
114114
// CHECK:STDOUT: inst44: concrete_constant(inst45)
@@ -123,7 +123,7 @@ fn Foo(n: ()) -> ((), ()) {
123123
// CHECK:STDOUT: inst_blocks:
124124
// CHECK:STDOUT: inst_block_empty: {}
125125
// CHECK:STDOUT: exports:
126-
// CHECK:STDOUT: 0: inst36
126+
// CHECK:STDOUT: 0: inst37
127127
// CHECK:STDOUT: imports: {}
128128
// CHECK:STDOUT: global_init: {}
129129
// CHECK:STDOUT: inst_block4:
@@ -138,28 +138,28 @@ fn Foo(n: ()) -> ((), ()) {
138138
// CHECK:STDOUT: 0: inst15
139139
// CHECK:STDOUT: 1: inst15
140140
// CHECK:STDOUT: inst_block8:
141-
// CHECK:STDOUT: 0: inst26
142-
// CHECK:STDOUT: 1: inst27
141+
// CHECK:STDOUT: 0: inst27
142+
// CHECK:STDOUT: 1: inst28
143143
// CHECK:STDOUT: inst_block9:
144-
// CHECK:STDOUT: 0: inst32
145-
// CHECK:STDOUT: 1: inst34
144+
// CHECK:STDOUT: 0: inst33
145+
// CHECK:STDOUT: 1: inst35
146146
// CHECK:STDOUT: inst_block10:
147147
// CHECK:STDOUT: 0: inst20
148148
// CHECK:STDOUT: 1: inst21
149-
// CHECK:STDOUT: 2: inst30
150-
// CHECK:STDOUT: 3: inst31
149+
// CHECK:STDOUT: 2: inst31
150+
// CHECK:STDOUT: 3: inst32
151151
// CHECK:STDOUT: inst_block11:
152152
// CHECK:STDOUT: 0: inst22
153153
// CHECK:STDOUT: 1: inst23
154154
// CHECK:STDOUT: 2: inst25
155-
// CHECK:STDOUT: 3: inst26
156-
// CHECK:STDOUT: 4: inst27
157-
// CHECK:STDOUT: 5: inst28
158-
// CHECK:STDOUT: 6: inst32
159-
// CHECK:STDOUT: 7: inst33
155+
// CHECK:STDOUT: 3: inst27
156+
// CHECK:STDOUT: 4: inst28
157+
// CHECK:STDOUT: 5: inst29
158+
// CHECK:STDOUT: 6: inst33
159+
// CHECK:STDOUT: 7: inst34
160160
// CHECK:STDOUT: 8: inst18
161-
// CHECK:STDOUT: 9: inst34
162-
// CHECK:STDOUT: 10: inst35
161+
// CHECK:STDOUT: 9: inst35
162+
// CHECK:STDOUT: 10: inst36
163163
// CHECK:STDOUT: inst_block12:
164164
// CHECK:STDOUT: 0: inst40
165165
// CHECK:STDOUT: 1: inst41
@@ -185,7 +185,7 @@ fn Foo(n: ()) -> ((), ()) {
185185
// CHECK:STDOUT: 1: inst45
186186
// CHECK:STDOUT: inst_block17:
187187
// CHECK:STDOUT: 0: inst14
188-
// CHECK:STDOUT: 1: inst36
188+
// CHECK:STDOUT: 1: inst37
189189
// CHECK:STDOUT: ...
190190
// CHECK:STDOUT: --- one_file_with_textual_ir.carbon
191191
// CHECK:STDOUT:
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
2+
// Exceptions. See /LICENSE for license information.
3+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
//
5+
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/int.carbon
6+
//
7+
// AUTOUPDATE
8+
// TIP: To test this file alone, run:
9+
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/adapter/convert_incomplete.carbon
10+
// TIP: To dump output, run:
11+
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/adapter/convert_incomplete.carbon
12+
13+
// --- already_complete.carbon
14+
15+
library "[[@TEST_NAME]]";
16+
17+
class Adapter(T:! type) {
18+
extend adapt T*;
19+
}
20+
21+
class X {}
22+
23+
// Trigger completion of Adapter(X) here.
24+
var x: Adapter(X);
25+
26+
fn F(p: Adapter(X)*) {
27+
let x: X* = *p as X*;
28+
}
29+
30+
// --- can_be_completed.carbon
31+
32+
library "[[@TEST_NAME]]";
33+
34+
class Adapter(T:! type) {
35+
extend adapt T*;
36+
}
37+
38+
class X {}
39+
40+
fn F(p: Adapter(X)*) {
41+
// The conversion here triggers completion of Adapter(X)
42+
// so we can determine what it adapts.
43+
let x: X* = *p as X*;
44+
}
45+
46+
// --- fail_incomplete.carbon
47+
48+
library "[[@TEST_NAME]]";
49+
50+
class Adapter(T:! type);
51+
52+
class X {}
53+
54+
fn F(p: Adapter(X)*) {
55+
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+7]]:15: error: cannot convert expression of type `Adapter(X)` to `X*` with `as` [ConversionFailure]
56+
// CHECK:STDERR: let x: X* = *p as X*;
57+
// CHECK:STDERR: ^~~~~~~~
58+
// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+4]]:15: note: type `Adapter(X)` does not implement interface `Core.As(X*)` [MissingImplInMemberAccessNote]
59+
// CHECK:STDERR: let x: X* = *p as X*;
60+
// CHECK:STDERR: ^~~~~~~~
61+
// CHECK:STDERR:
62+
let x: X* = *p as X*;
63+
}

0 commit comments

Comments
 (0)