فهرست منبع

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
Jacob Schneider 2 سال پیش
والد
کامیت
a4c0febc0f
3فایلهای تغییر یافته به همراه48 افزوده شده و 17 حذف شده
  1. 23 13
      explorer/interpreter/type_checker.cpp
  2. 4 4
      explorer/interpreter/type_checker.h
  3. 21 0
      explorer/testdata/addr/fail_missing_addr.carbon

+ 23 - 13
explorer/interpreter/type_checker.cpp

@@ -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;

+ 4 - 4
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<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
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;
+}