Просмотр исходного кода

Fix for: missing check that deduced argument converts to type of parameter #1300 (#1918)

Fix #1300

Co-authored-by: m new <michael.burzan@outlook.de>
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
pmqtt 3 лет назад
Родитель
Сommit
2c921efe36

+ 18 - 2
explorer/interpreter/type_checker.cpp

@@ -516,6 +516,7 @@ auto TypeChecker::ImplicitlyConvert(const std::string& context,
                                     Nonnull<const Value*> destination)
     -> ErrorOr<Nonnull<Expression*>> {
   Nonnull<const Value*> source_type = &source->static_type();
+
   // TODO: If a builtin conversion works, for now we don't create any
   // expression to do the conversion and rely on the interpreter to know how to
   // do it.
@@ -659,6 +660,18 @@ auto TypeChecker::ArgumentDeduction(
   switch (param->kind()) {
     case Value::Kind::VariableType: {
       const auto& var_type = cast<VariableType>(*param);
+      const auto& binding = cast<VariableType>(*param).binding();
+      if (binding.has_static_type()) {
+        const Value* binding_type = Substitute(deduced, &binding.static_type());
+        if (!IsTypeOfType(binding_type)) {
+          if (!IsImplicitlyConvertible(arg, binding_type, impl_scope, false)) {
+            return CompilationError(source_loc)
+                   << "cannot convert deduced value " << *arg << " for "
+                   << binding.name() << " to parameter type " << *binding_type;
+          }
+        }
+      }
+
       if (std::find(bindings_to_deduce.begin(), bindings_to_deduce.end(),
                     &var_type.binding()) != bindings_to_deduce.end()) {
         auto [it, success] = deduced.insert({&var_type.binding(), arg});
@@ -840,8 +853,9 @@ auto TypeChecker::ArgumentDeduction(
     case Value::Kind::TypeOfConstraintType:
     case Value::Kind::TypeOfChoiceType:
     case Value::Kind::TypeOfParameterizedEntityName:
-    case Value::Kind::TypeOfMemberName:
+    case Value::Kind::TypeOfMemberName: {
       return handle_non_deduced_type();
+    }
     case Value::Kind::ImplWitness:
     case Value::Kind::SymbolicWitness:
     case Value::Kind::ParameterizedEntityName:
@@ -1314,7 +1328,6 @@ auto TypeChecker::DeduceCallBindings(
            << "wrong number of arguments in function call, expected "
            << params.size() << " but got " << args.size();
   }
-
   // Bindings for deduced parameters and generic parameters.
   BindingMap generic_bindings;
 
@@ -1370,9 +1383,12 @@ auto TypeChecker::DeduceCallBindings(
 
   // Convert the arguments to the parameter type.
   Nonnull<const Value*> param_type = Substitute(generic_bindings, params_type);
+
+  // Convert the arguments to the deduced and substituted parameter type.
   CARBON_ASSIGN_OR_RETURN(
       Nonnull<Expression*> converted_argument,
       ImplicitlyConvert("call", impl_scope, &call.argument(), param_type));
+
   call.set_argument(converted_argument);
 
   return Success();

+ 23 - 0
explorer/testdata/generic_function/fail_wrong_variable_substituation.carbon

@@ -0,0 +1,23 @@
+// 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
+//
+// RUN: %{not} %{explorer} %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
+// RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
+// RUN:   %{FileCheck} --match-full-lines --allow-unused-prefixes %s
+// AUTOUPDATE: %{explorer} %s
+
+package Foo api;
+
+class X{
+}
+
+fn Get[T:! ()](n: T) -> i32 {  return 2; }
+
+fn Main() -> i32 {
+  var x : X = {};
+  // CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/generic_function/fail_wrong_variable_substituation.carbon:[[@LINE+1]]: cannot convert deduced value class X for T to parameter type ()
+  Get(x);
+  return 0;
+}