|
@@ -549,6 +549,11 @@ auto TypeChecker::ImplicitlyConvert(std::string_view context,
|
|
|
destination));
|
|
destination));
|
|
|
CARBON_ASSIGN_OR_RETURN(Nonnull<const Value*> source_value,
|
|
CARBON_ASSIGN_OR_RETURN(Nonnull<const Value*> source_value,
|
|
|
InterpExp(source, arena_, trace_stream_));
|
|
InterpExp(source, arena_, trace_stream_));
|
|
|
|
|
+ if (trace_stream_) {
|
|
|
|
|
+ **trace_stream_ << "converting type " << *source_value
|
|
|
|
|
+ << " to constraint " << *destination_constraint << " for "
|
|
|
|
|
+ << context << " in scope " << impl_scope << "\n";
|
|
|
|
|
+ }
|
|
|
// Note, we discard the witness. We don't actually need it in order to
|
|
// Note, we discard the witness. We don't actually need it in order to
|
|
|
// perform the conversion, but we do want to know it exists.
|
|
// perform the conversion, but we do want to know it exists.
|
|
|
CARBON_RETURN_IF_ERROR(impl_scope.Resolve(
|
|
CARBON_RETURN_IF_ERROR(impl_scope.Resolve(
|
|
@@ -756,15 +761,6 @@ auto TypeChecker::ArgumentDeduction::Deduce(Nonnull<const Value*> param,
|
|
|
// different forms. In this case, we require an implicit conversion to exist,
|
|
// different forms. In this case, we require an implicit conversion to exist,
|
|
|
// or for an exact type match if implicit conversions are not permitted.
|
|
// or for an exact type match if implicit conversions are not permitted.
|
|
|
auto handle_non_deduced_type = [&]() -> ErrorOr<Success> {
|
|
auto handle_non_deduced_type = [&]() -> ErrorOr<Success> {
|
|
|
- if (!IsConcreteType(param)) {
|
|
|
|
|
- // Parameter type contains a nested `auto` and argument type isn't the
|
|
|
|
|
- // same kind of type.
|
|
|
|
|
- // TODO: This seems like something we should be able to accept.
|
|
|
|
|
- return ProgramError(source_loc_) << "type error in " << context_ << "\n"
|
|
|
|
|
- << "expected: " << *param << "\n"
|
|
|
|
|
- << "actual: " << *arg;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
if (ValueEqual(param, arg, std::nullopt)) {
|
|
if (ValueEqual(param, arg, std::nullopt)) {
|
|
|
return Success();
|
|
return Success();
|
|
|
}
|
|
}
|
|
@@ -1112,7 +1108,7 @@ class TypeChecker::ConstraintTypeBuilder {
|
|
|
ConstraintTypeBuilder(Nonnull<Arena*> arena,
|
|
ConstraintTypeBuilder(Nonnull<Arena*> arena,
|
|
|
Nonnull<GenericBinding*> self_binding)
|
|
Nonnull<GenericBinding*> self_binding)
|
|
|
: arena_(arena),
|
|
: arena_(arena),
|
|
|
- self_binding_(PrepareSelfBinding(arena, self_binding)),
|
|
|
|
|
|
|
+ self_binding_(self_binding),
|
|
|
impl_binding_(AddImplBinding(arena, self_binding_)) {}
|
|
impl_binding_(AddImplBinding(arena, self_binding_)) {}
|
|
|
ConstraintTypeBuilder(Nonnull<Arena*> arena,
|
|
ConstraintTypeBuilder(Nonnull<Arena*> arena,
|
|
|
Nonnull<GenericBinding*> self_binding,
|
|
Nonnull<GenericBinding*> self_binding,
|
|
@@ -1392,25 +1388,24 @@ class TypeChecker::ConstraintTypeBuilder {
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // Sets up a `.Self` binding to act as the self type of a constraint.
|
|
|
|
|
+ static void PrepareSelfBinding(Nonnull<Arena*> arena,
|
|
|
|
|
+ Nonnull<GenericBinding*> self_binding) {
|
|
|
|
|
+ Nonnull<const Value*> self = arena->New<VariableType>(self_binding);
|
|
|
|
|
+ self_binding->set_symbolic_identity(self);
|
|
|
|
|
+ self_binding->set_value(self);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private:
|
|
private:
|
|
|
- // Makes a generic binding to serve as the `.Self` of this constraint type.
|
|
|
|
|
|
|
+ // Makes a generic binding to serve as the `.Self` of a constraint type.
|
|
|
static auto MakeSelfBinding(Nonnull<Arena*> arena, SourceLocation source_loc)
|
|
static auto MakeSelfBinding(Nonnull<Arena*> arena, SourceLocation source_loc)
|
|
|
-> Nonnull<GenericBinding*> {
|
|
-> Nonnull<GenericBinding*> {
|
|
|
// Note, the type-of-type here is a placeholder and isn't really
|
|
// Note, the type-of-type here is a placeholder and isn't really
|
|
|
// meaningful.
|
|
// meaningful.
|
|
|
- return arena->New<GenericBinding>(source_loc, ".Self",
|
|
|
|
|
- arena->New<TypeTypeLiteral>(source_loc));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Sets up a `.Self` binding to act as the self type of this constraint.
|
|
|
|
|
- static auto PrepareSelfBinding(Nonnull<Arena*> arena,
|
|
|
|
|
- Nonnull<GenericBinding*> self_binding)
|
|
|
|
|
- -> Nonnull<GenericBinding*> {
|
|
|
|
|
- Nonnull<const Value*> self = arena->New<VariableType>(self_binding);
|
|
|
|
|
- // TODO: Do we really need both of these?
|
|
|
|
|
- self_binding->set_symbolic_identity(self);
|
|
|
|
|
- self_binding->set_value(self);
|
|
|
|
|
- return self_binding;
|
|
|
|
|
|
|
+ auto* result = arena->New<GenericBinding>(
|
|
|
|
|
+ source_loc, ".Self", arena->New<TypeTypeLiteral>(source_loc));
|
|
|
|
|
+ PrepareSelfBinding(arena, result);
|
|
|
|
|
+ return result;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Adds an impl binding to the given self binding.
|
|
// Adds an impl binding to the given self binding.
|
|
@@ -2063,6 +2058,7 @@ auto TypeChecker::LookupRewriteInTypeOf(
|
|
|
// We looked for a rewrite before we finished type-checking the generic
|
|
// We looked for a rewrite before we finished type-checking the generic
|
|
|
// binding. This happens when forming the type of a generic binding. Just
|
|
// binding. This happens when forming the type of a generic binding. Just
|
|
|
// say there are no rewrites yet.
|
|
// say there are no rewrites yet.
|
|
|
|
|
+ // TODO: `.Self` substitution should fix this.
|
|
|
return std::nullopt;
|
|
return std::nullopt;
|
|
|
}
|
|
}
|
|
|
return LookupRewrite(&var_type->binding().static_type(), interface, member);
|
|
return LookupRewrite(&var_type->binding().static_type(), interface, member);
|
|
@@ -2074,8 +2070,10 @@ auto TypeChecker::LookupRewriteInTypeOf(
|
|
|
if (const auto* assoc_const = dyn_cast<AssociatedConstant>(type)) {
|
|
if (const auto* assoc_const = dyn_cast<AssociatedConstant>(type)) {
|
|
|
if (!assoc_const->constant().has_static_type()) {
|
|
if (!assoc_const->constant().has_static_type()) {
|
|
|
// We looked for a rewrite before we finished type-checking the
|
|
// We looked for a rewrite before we finished type-checking the
|
|
|
- // associated constant. This can happens when a use of `.Self` occurs
|
|
|
|
|
- // within the constant's type. Just say there are no rewrites yet.
|
|
|
|
|
|
|
+ // associated constant. This happens when forming the type of the
|
|
|
|
|
+ // associated constant, if `.Self` is used to access an associated
|
|
|
|
|
+ // constant. Just say that there are not rewrites yet.
|
|
|
|
|
+ // TODO: `.Self` substitution should fix this.
|
|
|
return std::nullopt;
|
|
return std::nullopt;
|
|
|
}
|
|
}
|
|
|
// The following is an expanded version of
|
|
// The following is an expanded version of
|
|
@@ -3208,6 +3206,18 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
|
|
inner_impl_scope.AddParent(&impl_scope);
|
|
inner_impl_scope.AddParent(&impl_scope);
|
|
|
|
|
|
|
|
auto& self = where.self_binding();
|
|
auto& self = where.self_binding();
|
|
|
|
|
+
|
|
|
|
|
+ // If there's some enclosing `.Self` value, our self is symbolically
|
|
|
|
|
+ // equal to that. Otherwise it's a new type variable.
|
|
|
|
|
+ if (auto enclosing_dot_self = where.enclosing_dot_self()) {
|
|
|
|
|
+ // TODO: We need to also enforce that our `.Self` does end up being the
|
|
|
|
|
+ // same as the enclosing type.
|
|
|
|
|
+ self.set_symbolic_identity(*(*enclosing_dot_self)->symbolic_identity());
|
|
|
|
|
+ self.set_value(&(*enclosing_dot_self)->value());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ConstraintTypeBuilder::PrepareSelfBinding(arena_, &self);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
ConstraintTypeBuilder builder(arena_, &self);
|
|
ConstraintTypeBuilder builder(arena_, &self);
|
|
|
ConstraintTypeBuilder::ConstraintsInScopeTracker constraint_tracker;
|
|
ConstraintTypeBuilder::ConstraintsInScopeTracker constraint_tracker;
|
|
|
|
|
|
|
@@ -3322,7 +3332,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
|
|
CARBON_ASSIGN_OR_RETURN(
|
|
CARBON_ASSIGN_OR_RETURN(
|
|
|
Nonnull<Expression*> converted_expression,
|
|
Nonnull<Expression*> converted_expression,
|
|
|
ImplicitlyConvert(
|
|
ImplicitlyConvert(
|
|
|
- "rewrite constraint", impl_scope, replacement_literal,
|
|
|
|
|
|
|
+ "rewrite constraint", inner_impl_scope, replacement_literal,
|
|
|
GetTypeForAssociatedConstant(constant_value)));
|
|
GetTypeForAssociatedConstant(constant_value)));
|
|
|
CARBON_ASSIGN_OR_RETURN(
|
|
CARBON_ASSIGN_OR_RETURN(
|
|
|
Nonnull<const Value*> converted_value,
|
|
Nonnull<const Value*> converted_value,
|
|
@@ -4434,6 +4444,7 @@ auto TypeChecker::DeclareInterfaceDeclaration(
|
|
|
self_type->set_constant_value(iface_type);
|
|
self_type->set_constant_value(iface_type);
|
|
|
|
|
|
|
|
// Build a constraint corresponding to this interface.
|
|
// Build a constraint corresponding to this interface.
|
|
|
|
|
+ ConstraintTypeBuilder::PrepareSelfBinding(arena_, iface_decl->self());
|
|
|
ConstraintTypeBuilder builder(arena_, iface_decl->self());
|
|
ConstraintTypeBuilder builder(arena_, iface_decl->self());
|
|
|
ConstraintTypeBuilder::ConstraintsInScopeTracker constraint_tracker;
|
|
ConstraintTypeBuilder::ConstraintsInScopeTracker constraint_tracker;
|
|
|
iface_decl->self()->set_static_type(iface_type);
|
|
iface_decl->self()->set_static_type(iface_type);
|