diff --git a/toolchain/check/handle_impl.cpp b/toolchain/check/handle_impl.cpp index 4589062367e78..808aa89d44d4e 100644 --- a/toolchain/check/handle_impl.cpp +++ b/toolchain/check/handle_impl.cpp @@ -102,6 +102,7 @@ auto HandleParseNode(Context& context, Parse::DefaultSelfImplAsId node_id) "`impl as` can only be used in a class"); context.emitter().Emit(node_id, ImplAsOutsideClass); self_type_id = SemIR::ErrorInst::SingletonTypeId; + return false; } // Build the implicit access to the enclosing `Self`. diff --git a/toolchain/check/testdata/function/declaration/no_prelude/name_poisoning.carbon b/toolchain/check/testdata/function/declaration/no_prelude/name_poisoning.carbon index 86b6cd9d32a23..aaf0bcd681254 100644 --- a/toolchain/check/testdata/function/declaration/no_prelude/name_poisoning.carbon +++ b/toolchain/check/testdata/function/declaration/no_prelude/name_poisoning.carbon @@ -239,9 +239,10 @@ library "[[@TEST_NAME]]"; class C {} namespace N; -// CHECK:STDERR: fail_alias.carbon:[[@LINE+3]]:9: note: declared here [NameUseBeforeDeclNote] +// CHECK:STDERR: fail_alias.carbon:[[@LINE+4]]:9: note: declared here [NameUseBeforeDeclNote] // CHECK:STDERR: alias N.C = C; // CHECK:STDERR: ^ +// CHECK:STDERR: alias N.C = C; // --- ignored_poison_in_import.carbon @@ -259,6 +260,38 @@ impl library "[[@TEST_NAME]]"; // TODO: This should fail since N.C was poisoned in the api. class N.C {} +// --- using_poisoned_name_in_impl.carbon + +library "[[@TEST_NAME]]"; + +interface C {}; + +namespace N; +// Here we use C and poison N.C. +fn N.F1(x: C); + +class N.X { + extend impl as C { + } +} + +// --- fail_using_poisoned_name_in_impl_outside_class.carbon + +library "[[@TEST_NAME]]"; + +interface A { + fn B(); +} +class X { + extend impl as A { + fn F() { return; } + // CHECK:STDERR: fail_using_poisoned_name_in_impl_outside_class.carbon:[[@LINE+3]]:10: error: `impl as` can only be used in a class [ImplAsOutsideClass] + // CHECK:STDERR: impl as B {} + // CHECK:STDERR: ^~ + impl as B {} + } +} + // CHECK:STDOUT: --- no_poison.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -923,7 +956,7 @@ class N.C {} // CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} {} // CHECK:STDOUT: %N: = namespace [template] {} // CHECK:STDOUT: %C.ref: type = name_ref C, %C.decl [template = constants.%C] -// CHECK:STDOUT: %.loc11: type = bind_alias , %C.decl [template = constants.%C] +// CHECK:STDOUT: %.loc12: type = bind_alias , %C.decl [template = constants.%C] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @C { @@ -1003,3 +1036,109 @@ class N.C {} // CHECK:STDOUT: complete_type_witness = %complete_type // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- using_poisoned_name_in_impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C.type: type = facet_type <@C> [template] +// CHECK:STDOUT: %Self: %C.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %F1.type: type = fn_type @F1 [template] +// CHECK:STDOUT: %F1: %F1.type = struct_value () [template] +// CHECK:STDOUT: %X: type = class_type @X [template] +// CHECK:STDOUT: %impl_witness: = impl_witness () [template] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [template] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .N = %N +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = interface_decl @C [template = constants.%C.type] {} {} +// CHECK:STDOUT: %N: = namespace [template] { +// CHECK:STDOUT: .F1 = %F1.decl +// CHECK:STDOUT: .X = %X.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %F1.decl: %F1.type = fn_decl @F1 [template = constants.%F1] { +// CHECK:STDOUT: %x.patt: %C.type = binding_pattern x +// CHECK:STDOUT: %x.param_patt: %C.type = value_param_pattern %x.patt, runtime_param0 +// CHECK:STDOUT: } { +// CHECK:STDOUT: %x.param: %C.type = value_param runtime_param0 +// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [template = constants.%C.type] +// CHECK:STDOUT: %x: %C.type = bind_name x, %x.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %X.decl: type = class_decl @X [template = constants.%X] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @C { +// CHECK:STDOUT: %Self: %C.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl: %Self.ref as %C.ref { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: witness = @X.%impl_witness +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @X { +// CHECK:STDOUT: impl_decl @impl [template] {} { +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%X [template = constants.%X] +// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [template = constants.%C.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %impl_witness: = impl_witness () [template = constants.%impl_witness] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [template = constants.%complete_type] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%X +// CHECK:STDOUT: extend @impl.%C.ref +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F1(%x.param_patt: %C.type); +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_using_poisoned_name_in_impl_outside_class.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %A.type: type = facet_type <@A> [template] +// CHECK:STDOUT: %Self: %A.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %B.type: type = fn_type @B [template] +// CHECK:STDOUT: %B: %B.type = struct_value () [template] +// CHECK:STDOUT: %B.assoc_type: type = assoc_entity_type %A.type, %B.type [template] +// CHECK:STDOUT: %assoc0: %B.assoc_type = assoc_entity element0, @A.%B.decl [template] +// CHECK:STDOUT: %X: type = class_type @X [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file {} +// CHECK:STDOUT: +// CHECK:STDOUT: interface @A { +// CHECK:STDOUT: %Self: %A.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self] +// CHECK:STDOUT: %B.decl: %B.type = fn_decl @B [template = constants.%B] {} {} +// CHECK:STDOUT: %assoc0: %B.assoc_type = assoc_entity element0, %B.decl [template = constants.%assoc0] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .B = %assoc0 +// CHECK:STDOUT: witness = (%B.decl) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl: .inst26.loc8_15 as .inst27.loc8_18; +// CHECK:STDOUT: +// CHECK:STDOUT: class @X { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%X +// CHECK:STDOUT: extend .inst27.loc8_18 +// CHECK:STDOUT: complete_type_witness = invalid +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @B(@A.%Self: %A.type) { +// CHECK:STDOUT: +// CHECK:STDOUT: fn(); +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(); +// CHECK:STDOUT: +// CHECK:STDOUT: specific @B(constants.%Self) {} +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/fail_impl_as_scope.carbon b/toolchain/check/testdata/impl/fail_impl_as_scope.carbon index 393a866eb34e9..6de910c368fab 100644 --- a/toolchain/check/testdata/impl/fail_impl_as_scope.carbon +++ b/toolchain/check/testdata/impl/fail_impl_as_scope.carbon @@ -24,39 +24,17 @@ impl as Simple { // CHECK:STDOUT: constants { // CHECK:STDOUT: %Simple.type: type = facet_type <@Simple> [template] // CHECK:STDOUT: %Self: %Simple.type = bind_symbolic_name Self, 0 [symbolic] -// CHECK:STDOUT: %F.type.1: type = fn_type @F.1 [template] -// CHECK:STDOUT: %F.1: %F.type.1 = struct_value () [template] -// CHECK:STDOUT: %F.assoc_type: type = assoc_entity_type %Simple.type, %F.type.1 [template] +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %F.assoc_type: type = assoc_entity_type %Simple.type, %F.type [template] // CHECK:STDOUT: %assoc0: %F.assoc_type = assoc_entity element0, @Simple.%F.decl [template] -// CHECK:STDOUT: %impl_witness: = impl_witness (@impl.%F.decl) [template] -// CHECK:STDOUT: %F.type.2: type = fn_type @F.2 [template] -// CHECK:STDOUT: %F.2: %F.type.2 = struct_value () [template] // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: imports { -// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { -// CHECK:STDOUT: import Core//prelude -// CHECK:STDOUT: import Core//prelude/... -// CHECK:STDOUT: } -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace [template] { -// CHECK:STDOUT: .Core = imports.%Core -// CHECK:STDOUT: .Simple = %Simple.decl -// CHECK:STDOUT: } -// CHECK:STDOUT: %Core.import = import Core -// CHECK:STDOUT: %Simple.decl: type = interface_decl @Simple [template = constants.%Simple.type] {} {} -// CHECK:STDOUT: impl_decl @impl [template] {} { -// CHECK:STDOUT: %Self.ref: type = name_ref Self, [template = ] -// CHECK:STDOUT: %Simple.ref: type = name_ref Simple, file.%Simple.decl [template = constants.%Simple.type] -// CHECK:STDOUT: } -// CHECK:STDOUT: %impl_witness: = impl_witness (@impl.%F.decl) [template = constants.%impl_witness] -// CHECK:STDOUT: } +// CHECK:STDOUT: file {} // CHECK:STDOUT: // CHECK:STDOUT: interface @Simple { // CHECK:STDOUT: %Self: %Simple.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self] -// CHECK:STDOUT: %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] {} {} +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {} // CHECK:STDOUT: %assoc0: %F.assoc_type = assoc_entity element0, %F.decl [template = constants.%assoc0] // CHECK:STDOUT: // CHECK:STDOUT: !members: @@ -65,25 +43,10 @@ impl as Simple { // CHECK:STDOUT: witness = (%F.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @impl: %Self.ref as %Simple.ref { -// CHECK:STDOUT: %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {} -// CHECK:STDOUT: -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .F = %F.decl -// CHECK:STDOUT: witness = file.%impl_witness -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: generic fn @F.1(@Simple.%Self: %Simple.type) { +// CHECK:STDOUT: generic fn @F(@Simple.%Self: %Simple.type) { // CHECK:STDOUT: // CHECK:STDOUT: fn(); // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.2() { -// CHECK:STDOUT: !entry: -// CHECK:STDOUT: return -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: specific @F.1(constants.%Self) {} -// CHECK:STDOUT: -// CHECK:STDOUT: specific @F.1() {} +// CHECK:STDOUT: specific @F(constants.%Self) {} // CHECK:STDOUT: