diff --git a/explorer/interpreter/type_checker.cpp b/explorer/interpreter/type_checker.cpp index 0e8d077fae17..536d2b109f4b 100644 --- a/explorer/interpreter/type_checker.cpp +++ b/explorer/interpreter/type_checker.cpp @@ -516,6 +516,7 @@ auto TypeChecker::ImplicitlyConvert(const std::string& context, Nonnull destination) -> ErrorOr> { Nonnull 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(*param); + const auto& binding = cast(*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 param_type = Substitute(generic_bindings, params_type); + + // Convert the arguments to the deduced and substituted parameter type. CARBON_ASSIGN_OR_RETURN( Nonnull converted_argument, ImplicitlyConvert("call", impl_scope, &call.argument(), param_type)); + call.set_argument(converted_argument); return Success(); diff --git a/explorer/testdata/generic_function/fail_wrong_variable_substituation.carbon b/explorer/testdata/generic_function/fail_wrong_variable_substituation.carbon new file mode 100644 index 000000000000..169b9b4e4bd5 --- /dev/null +++ b/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; +}