Skip to content

Commit

Permalink
Add a test for the case that impl function is poisoned (#4950)
Browse files Browse the repository at this point in the history
This adds missing coverage.
Part of #4622.
  • Loading branch information
bricknerb authored Feb 28, 2025
1 parent f7e0b61 commit fc5dcfe
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ alias N.F2 = F1;
fn N.F1();

// Failure: `N.F1` used after declaration failed.
// TODO: #4622 - Allow defining a poisoned name so it would be found if used after it's declared.
// CHECK:STDERR: fail_use_declaration_after_poison.carbon:[[@LINE+4]]:14: error: member name `F1` not found in `N` [MemberNameNotFoundInScope]
// CHECK:STDERR: alias N.F3 = N.F1;
// CHECK:STDERR: ^~~~
Expand Down Expand Up @@ -414,7 +415,7 @@ fn F1() {
// CHECK:STDOUT: %F2: %F1.type.75d = bind_alias F2, %F1.decl.loc4 [concrete = constants.%F1.afe]
// CHECK:STDOUT: %F1.decl.loc18: %F1.type.fe6 = fn_decl @F1.2 [concrete = constants.%F1.cc1] {} {}
// CHECK:STDOUT: %N.ref: <namespace> = name_ref N, %N [concrete = %N]
// CHECK:STDOUT: %F1.ref.loc25: <error> = name_ref F1, <error> [concrete = <error>]
// CHECK:STDOUT: %F1.ref.loc26: <error> = name_ref F1, <error> [concrete = <error>]
// CHECK:STDOUT: %F3: <error> = bind_alias F3, <error> [concrete = <error>]
// CHECK:STDOUT: }
// CHECK:STDOUT:
Expand Down
148 changes: 148 additions & 0 deletions toolchain/check/testdata/impl/no_prelude/name_poisoning.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,37 @@ class N.C {
}
}

// --- fail_impl_function_poisoned.carbon

library "[[@TEST_NAME]]";

interface I {
fn A(x: Self);
fn B();
}

class B {
impl as I {
// CHECK:STDERR: fail_impl_function_poisoned.carbon:[[@LINE+3]]:13: error: name `B` used before it was declared [NameUseBeforeDecl]
// CHECK:STDERR: fn A(x: B);
// CHECK:STDERR: ^
fn A(x: B);
// TODO: Avoid ImplMissingFunction for functions that were declared after they were poisoned.
// CHECK:STDERR: fail_impl_function_poisoned.carbon:[[@LINE+11]]:8: note: declared here [NameUseBeforeDeclNote]
// CHECK:STDERR: fn B();
// CHECK:STDERR: ^
// CHECK:STDERR:
// CHECK:STDERR: fail_impl_function_poisoned.carbon:[[@LINE-10]]:3: error: missing implementation of B in impl of interface I [ImplMissingFunction]
// CHECK:STDERR: impl as I {
// CHECK:STDERR: ^~~~~~~~~~~
// CHECK:STDERR: fail_impl_function_poisoned.carbon:[[@LINE-17]]:3: note: associated function B declared here [AssociatedFunctionHere]
// CHECK:STDERR: fn B();
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
fn B();
}
}

// CHECK:STDOUT: --- using_poisoned_name_in_impl.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
Expand Down Expand Up @@ -100,3 +131,120 @@ class N.C {
// CHECK:STDOUT: %x.patt.loc8_9.2 => constants.%x
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_impl_function_poisoned.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %I.type: type = facet_type <@I> [concrete]
// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic]
// CHECK:STDOUT: %Self.as_type: type = facet_access_type %Self [symbolic]
// CHECK:STDOUT: %A.type.edf: type = fn_type @A.1 [concrete]
// CHECK:STDOUT: %A.ab0: %A.type.edf = struct_value () [concrete]
// CHECK:STDOUT: %I.assoc_type: type = assoc_entity_type %I.type [concrete]
// CHECK:STDOUT: %assoc0: %I.assoc_type = assoc_entity element0, @I.%A.decl [concrete]
// CHECK:STDOUT: %B.type.785: type = fn_type @B.1 [concrete]
// CHECK:STDOUT: %B.6d4: %B.type.785 = struct_value () [concrete]
// CHECK:STDOUT: %assoc1: %I.assoc_type = assoc_entity element1, @I.%B.decl [concrete]
// CHECK:STDOUT: %B.fa3: type = class_type @B.3 [concrete]
// CHECK:STDOUT: %impl_witness: <witness> = impl_witness (@impl.%A.decl, <error>) [concrete]
// CHECK:STDOUT: %A.type.9b9: type = fn_type @A.2 [concrete]
// CHECK:STDOUT: %A.71f: %A.type.9b9 = struct_value () [concrete]
// CHECK:STDOUT: %B.type.52d: type = fn_type @B.2 [concrete]
// CHECK:STDOUT: %B.30a: %B.type.52d = struct_value () [concrete]
// CHECK:STDOUT: %I.facet: %I.type = facet_value %B.fa3, %impl_witness [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .I = %I.decl
// CHECK:STDOUT: .B = %B.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %I.decl: type = interface_decl @I [concrete = constants.%I.type] {} {}
// CHECK:STDOUT: %B.decl: type = class_decl @B.3 [concrete = constants.%B.fa3] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: interface @I {
// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
// CHECK:STDOUT: %A.decl: %A.type.edf = fn_decl @A.1 [concrete = constants.%A.ab0] {
// CHECK:STDOUT: %x.patt: @A.1.%Self.as_type.loc5_11.1 (%Self.as_type) = binding_pattern x
// CHECK:STDOUT: %x.param_patt: @A.1.%Self.as_type.loc5_11.1 (%Self.as_type) = value_param_pattern %x.patt, runtime_param0
// CHECK:STDOUT: } {
// CHECK:STDOUT: %x.param: @A.1.%Self.as_type.loc5_11.1 (%Self.as_type) = value_param runtime_param0
// CHECK:STDOUT: %.loc5_11.1: type = splice_block %.loc5_11.2 [symbolic = %Self.as_type.loc5_11.1 (constants.%Self.as_type)] {
// CHECK:STDOUT: %Self.ref: %I.type = name_ref Self, @I.%Self [symbolic = %Self (constants.%Self)]
// CHECK:STDOUT: %Self.as_type.loc5_11.2: type = facet_access_type %Self.ref [symbolic = %Self.as_type.loc5_11.1 (constants.%Self.as_type)]
// CHECK:STDOUT: %.loc5_11.2: type = converted %Self.ref, %Self.as_type.loc5_11.2 [symbolic = %Self.as_type.loc5_11.1 (constants.%Self.as_type)]
// CHECK:STDOUT: }
// CHECK:STDOUT: %x: @A.1.%Self.as_type.loc5_11.1 (%Self.as_type) = bind_name x, %x.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %assoc0: %I.assoc_type = assoc_entity element0, %A.decl [concrete = constants.%assoc0]
// CHECK:STDOUT: %B.decl: %B.type.785 = fn_decl @B.1 [concrete = constants.%B.6d4] {} {}
// CHECK:STDOUT: %assoc1: %I.assoc_type = assoc_entity element1, %B.decl [concrete = constants.%assoc1]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = %Self
// CHECK:STDOUT: .A = %assoc0
// CHECK:STDOUT: .B = %assoc1
// CHECK:STDOUT: witness = (%A.decl, %B.decl)
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl: %Self.ref as %I.ref {
// CHECK:STDOUT: %A.decl: %A.type.9b9 = fn_decl @A.2 [concrete = constants.%A.71f] {
// CHECK:STDOUT: %x.patt: %B.fa3 = binding_pattern x
// CHECK:STDOUT: %x.param_patt: %B.fa3 = value_param_pattern %x.patt, runtime_param0
// CHECK:STDOUT: } {
// CHECK:STDOUT: %x.param: %B.fa3 = value_param runtime_param0
// CHECK:STDOUT: %B.ref: type = name_ref B, file.%B.decl [concrete = constants.%B.fa3]
// CHECK:STDOUT: %x: %B.fa3 = bind_name x, %x.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %B.decl: %B.type.52d = fn_decl @B.2 [concrete = constants.%B.30a] {} {}
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .B = <poisoned>
// CHECK:STDOUT: .A = %A.decl
// CHECK:STDOUT: witness = @B.3.%impl_witness
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @B.3 {
// CHECK:STDOUT: impl_decl @impl [concrete] {} {
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%B.fa3 [concrete = constants.%B.fa3]
// CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
// CHECK:STDOUT: }
// CHECK:STDOUT: %impl_witness: <witness> = impl_witness (@impl.%A.decl, <error>) [concrete = constants.%impl_witness]
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete = constants.%complete_type]
// CHECK:STDOUT: complete_type_witness = %complete_type
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%B.fa3
// CHECK:STDOUT: .I = <poisoned>
// CHECK:STDOUT: .B = <poisoned>
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic fn @A.1(@I.%Self: %I.type) {
// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)]
// CHECK:STDOUT: %Self.as_type.loc5_11.1: type = facet_access_type %Self [symbolic = %Self.as_type.loc5_11.1 (constants.%Self.as_type)]
// CHECK:STDOUT:
// CHECK:STDOUT: fn(%x.param_patt: @A.1.%Self.as_type.loc5_11.1 (%Self.as_type));
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic fn @B.1(@I.%Self: %I.type) {
// CHECK:STDOUT: fn();
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @A.2(%x.param_patt: %B.fa3);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @B.2();
// CHECK:STDOUT:
// CHECK:STDOUT: specific @A.1(constants.%Self) {
// CHECK:STDOUT: %Self => constants.%Self
// CHECK:STDOUT: %Self.as_type.loc5_11.1 => constants.%Self.as_type
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @B.1(constants.%Self) {}
// CHECK:STDOUT:
// CHECK:STDOUT: specific @A.1(constants.%I.facet) {
// CHECK:STDOUT: %Self => constants.%I.facet
// CHECK:STDOUT: %Self.as_type.loc5_11.1 => constants.%B.fa3
// CHECK:STDOUT: }
// CHECK:STDOUT:

0 comments on commit fc5dcfe

Please sign in to comment.