diff --git a/explorer/interpreter/type_checker.cpp b/explorer/interpreter/type_checker.cpp index 51c750617456..4a04829e1ee5 100644 --- a/explorer/interpreter/type_checker.cpp +++ b/explorer/interpreter/type_checker.cpp @@ -2733,19 +2733,29 @@ static auto IsInstanceMember(Nonnull element) { } } -auto TypeChecker::CheckAddrMeAccess( +auto TypeChecker::CheckAddrSelfAccess( Nonnull access, Nonnull func_decl, const Bindings& bindings, const ImplScope& impl_scope) -> ErrorOr { - if (func_decl->is_method() && - func_decl->self_pattern().kind() == PatternKind::AddrPattern) { + if (!func_decl->is_method()) { + return Success(); + } + + CARBON_ASSIGN_OR_RETURN( + Nonnull self_type, + Substitute(bindings, &func_decl->self_pattern().static_type())); + if (self_type->kind() == Value::Kind::PointerType && + access->object().static_type().kind() != Value::Kind::PointerType) { + return ProgramError(access->source_loc()) + << "method " << *access + << " does not match the target function's self pattern (did you " + "forget an `addr`?)"; + } + if (func_decl->self_pattern().kind() == PatternKind::AddrPattern) { access->set_is_addr_me_method(); - CARBON_ASSIGN_OR_RETURN( - Nonnull me_type, - Substitute(bindings, &func_decl->self_pattern().static_type())); - CARBON_RETURN_IF_ERROR( - ExpectExactType(access->source_loc(), "method access, receiver type", - me_type, &access->object().static_type(), impl_scope)); + CARBON_RETURN_IF_ERROR(ExpectExactType( + access->source_loc(), "method access, receiver type", self_type, + &access->object().static_type(), impl_scope)); if (access->object().expression_category() != ExpressionCategory::Reference) { return ProgramError(access->source_loc()) @@ -2916,7 +2926,7 @@ auto TypeChecker::TypeCheckExpImpl(Nonnull e, break; case DeclarationKind::FunctionDeclaration: { const auto* func_decl = cast(member); - CARBON_RETURN_IF_ERROR(CheckAddrMeAccess( + CARBON_RETURN_IF_ERROR(CheckAddrSelfAccess( &access, func_decl, t_class.bindings(), impl_scope)); if (access.is_type_access()) { access.set_static_type(field_type); @@ -3000,7 +3010,7 @@ auto TypeChecker::TypeCheckExpImpl(Nonnull e, if (const auto* func_decl = dyn_cast(result.member)) { CARBON_RETURN_IF_ERROR( - CheckAddrMeAccess(&access, func_decl, bindings, impl_scope)); + CheckAddrSelfAccess(&access, func_decl, bindings, impl_scope)); if (access.is_type_access()) { access.set_static_type(inst_member_type); } else { @@ -3344,8 +3354,8 @@ auto TypeChecker::TypeCheckExpImpl(Nonnull e, } access.set_expression_category(ExpressionCategory::Value); CARBON_RETURN_IF_ERROR( - CheckAddrMeAccess(&access, cast(*decl), - bindings_for_member(), impl_scope)); + CheckAddrSelfAccess(&access, cast(*decl), + bindings_for_member(), impl_scope)); return Success(); } break; diff --git a/explorer/interpreter/type_checker.h b/explorer/interpreter/type_checker.h index cb5ae26ae581..fb4de890aa29 100644 --- a/explorer/interpreter/type_checker.h +++ b/explorer/interpreter/type_checker.h @@ -182,10 +182,10 @@ class TypeChecker { // Checks a member access that might be accessing a function taking `addr // self: Self*`. If it does, this function marks the member access accordingly // and ensures the object argument is a reference expression. - auto CheckAddrMeAccess(Nonnull access, - Nonnull func_decl, - const Bindings& bindings, const ImplScope& impl_scope) - -> ErrorOr; + auto CheckAddrSelfAccess(Nonnull access, + Nonnull func_decl, + const Bindings& bindings, + const ImplScope& impl_scope) -> ErrorOr; // Traverses the AST rooted at `e`, populating the static_type() of all nodes // and ensuring they follow Carbon's typing rules. diff --git a/explorer/testdata/addr/fail_missing_addr.carbon b/explorer/testdata/addr/fail_missing_addr.carbon new file mode 100644 index 000000000000..8447350ea2b3 --- /dev/null +++ b/explorer/testdata/addr/fail_missing_addr.carbon @@ -0,0 +1,21 @@ +// 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 + +package ExplorerTest api; + +class Foo { + fn Bar[self: Foo*]() { + self->x += 1; + } + var x: i32; +} + +fn Main() -> i32 { + var foo: Foo = {.x = 0}; + // CHECK:STDERR: COMPILATION ERROR: fail_missing_addr.carbon:[[@LINE+1]]: method foo.Bar does not match the target function's self pattern (did you forget an `addr`?) + foo.Bar(); + return 0; +}