mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 17:31:07 +01:00
handle missing addr in self pointer pattern (#3369)
Add validation to `CheckAddrSelfAccess` to additionally check for situations where `addr` is potentially missing. I also updated the name of the function since `me` was renamed to `self`. Closes #3367
This commit is contained in:
@@ -2733,19 +2733,29 @@ static auto IsInstanceMember(Nonnull<const Element*> element) {
|
||||
}
|
||||
}
|
||||
|
||||
auto TypeChecker::CheckAddrMeAccess(
|
||||
auto TypeChecker::CheckAddrSelfAccess(
|
||||
Nonnull<MemberAccessExpression*> access,
|
||||
Nonnull<const FunctionDeclaration*> func_decl, const Bindings& bindings,
|
||||
const ImplScope& impl_scope) -> ErrorOr<Success> {
|
||||
if (func_decl->is_method() &&
|
||||
func_decl->self_pattern().kind() == PatternKind::AddrPattern) {
|
||||
if (!func_decl->is_method()) {
|
||||
return Success();
|
||||
}
|
||||
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
Nonnull<const Value*> 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<const Value*> 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<Expression*> e,
|
||||
break;
|
||||
case DeclarationKind::FunctionDeclaration: {
|
||||
const auto* func_decl = cast<FunctionDeclaration>(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<Expression*> e,
|
||||
if (const auto* func_decl =
|
||||
dyn_cast<FunctionDeclaration>(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<Expression*> e,
|
||||
}
|
||||
access.set_expression_category(ExpressionCategory::Value);
|
||||
CARBON_RETURN_IF_ERROR(
|
||||
CheckAddrMeAccess(&access, cast<FunctionDeclaration>(*decl),
|
||||
bindings_for_member(), impl_scope));
|
||||
CheckAddrSelfAccess(&access, cast<FunctionDeclaration>(*decl),
|
||||
bindings_for_member(), impl_scope));
|
||||
return Success();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -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<MemberAccessExpression*> access,
|
||||
Nonnull<const FunctionDeclaration*> func_decl,
|
||||
const Bindings& bindings, const ImplScope& impl_scope)
|
||||
-> ErrorOr<Success>;
|
||||
auto CheckAddrSelfAccess(Nonnull<MemberAccessExpression*> access,
|
||||
Nonnull<const FunctionDeclaration*> func_decl,
|
||||
const Bindings& bindings,
|
||||
const ImplScope& impl_scope) -> ErrorOr<Success>;
|
||||
|
||||
// Traverses the AST rooted at `e`, populating the static_type() of all nodes
|
||||
// and ensuring they follow Carbon's typing rules.
|
||||
|
||||
+21
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user