mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
This PR is making two main changes to the Explorer and Toolchain: - Replace the `is` keyword in `where SomeType is SomeInterface` with `impls`, so it is `where SomeType impls SomeInterface` - Rewrite uses of the "impls" to something else to avoid, frequently "`impl` declarations" or "implementations", to avoid confusion with the `impls` keyword. --------- Co-authored-by: Geoff Romer <gromer@google.com>
This commit is contained in:
@@ -134,7 +134,7 @@ message ArrayTypeLiteral {
|
||||
optional Expression size = 2;
|
||||
}
|
||||
|
||||
message IsWhereClause {
|
||||
message ImplsWhereClause {
|
||||
optional Expression type = 1;
|
||||
optional Expression constraint = 2;
|
||||
}
|
||||
@@ -151,7 +151,7 @@ message RewriteWhereClause {
|
||||
|
||||
message WhereClause {
|
||||
oneof kind {
|
||||
IsWhereClause is = 1;
|
||||
ImplsWhereClause impls = 1;
|
||||
EqualsWhereClause equals = 2;
|
||||
RewriteWhereClause rewrite = 3;
|
||||
}
|
||||
@@ -442,7 +442,7 @@ message ImplDeclaration {
|
||||
}
|
||||
|
||||
message MatchFirstDeclaration {
|
||||
repeated Declaration impls = 1;
|
||||
repeated Declaration impl_declarations = 1;
|
||||
}
|
||||
|
||||
message AliasDeclaration {
|
||||
|
||||
@@ -399,10 +399,10 @@ static auto ExpressionToCarbon(const Fuzzing::Expression& expression,
|
||||
for (const auto& clause : where.clauses()) {
|
||||
out << sep;
|
||||
switch (clause.kind_case()) {
|
||||
case Fuzzing::WhereClause::kIs:
|
||||
ExpressionToCarbon(clause.is().type(), out);
|
||||
out << " is ";
|
||||
ExpressionToCarbon(clause.is().constraint(), out);
|
||||
case Fuzzing::WhereClause::kImpls:
|
||||
ExpressionToCarbon(clause.impls().type(), out);
|
||||
out << " impls ";
|
||||
ExpressionToCarbon(clause.impls().constraint(), out);
|
||||
break;
|
||||
case Fuzzing::WhereClause::kEquals:
|
||||
ExpressionToCarbon(clause.equals().lhs(), out);
|
||||
@@ -970,7 +970,7 @@ static auto DeclarationToCarbon(const Fuzzing::Declaration& declaration,
|
||||
case Fuzzing::Declaration::kMatchFirst: {
|
||||
const auto& match_first = declaration.match_first();
|
||||
out << "__match_first {\n";
|
||||
for (const auto& impl : match_first.impls()) {
|
||||
for (const auto& impl : match_first.impl_declarations()) {
|
||||
DeclarationToCarbon(impl, out);
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ abstract class Expression : AstNode;
|
||||
class BuiltinConvertExpression : Expression;
|
||||
class UnimplementedExpression : Expression;
|
||||
abstract class WhereClause : AstNode;
|
||||
class IsWhereClause : WhereClause;
|
||||
class ImplsWhereClause : WhereClause;
|
||||
class EqualsWhereClause : WhereClause;
|
||||
class RewriteWhereClause : WhereClause;
|
||||
root class Element;
|
||||
|
||||
@@ -45,7 +45,8 @@ void Declaration::Print(llvm::raw_ostream& out) const {
|
||||
const auto& match_first_decl = cast<MatchFirstDeclaration>(*this);
|
||||
PrintID(out);
|
||||
out << " {\n";
|
||||
for (Nonnull<const ImplDeclaration*> m : match_first_decl.impls()) {
|
||||
for (Nonnull<const ImplDeclaration*> m :
|
||||
match_first_decl.impl_declarations()) {
|
||||
out << *m;
|
||||
}
|
||||
out << "}\n";
|
||||
|
||||
@@ -943,26 +943,31 @@ class ImplDeclaration : public Declaration {
|
||||
|
||||
class MatchFirstDeclaration : public Declaration {
|
||||
public:
|
||||
MatchFirstDeclaration(SourceLocation source_loc,
|
||||
std::vector<Nonnull<ImplDeclaration*>> impls)
|
||||
MatchFirstDeclaration(
|
||||
SourceLocation source_loc,
|
||||
std::vector<Nonnull<ImplDeclaration*>> impl_declarations)
|
||||
: Declaration(AstNodeKind::MatchFirstDeclaration, source_loc),
|
||||
impls_(std::move(impls)) {}
|
||||
impl_declarations_(std::move(impl_declarations)) {}
|
||||
|
||||
explicit MatchFirstDeclaration(CloneContext& context,
|
||||
const MatchFirstDeclaration& other)
|
||||
: Declaration(context, other), impls_(context.Clone(other.impls_)) {}
|
||||
: Declaration(context, other),
|
||||
impl_declarations_(context.Clone(other.impl_declarations_)) {}
|
||||
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromMatchFirstDeclaration(node->kind());
|
||||
}
|
||||
|
||||
auto impls() const -> llvm::ArrayRef<Nonnull<const ImplDeclaration*>> {
|
||||
return impls_;
|
||||
auto impl_declarations() const
|
||||
-> llvm::ArrayRef<Nonnull<const ImplDeclaration*>> {
|
||||
return impl_declarations_;
|
||||
}
|
||||
auto impl_declarations() -> llvm::ArrayRef<Nonnull<ImplDeclaration*>> {
|
||||
return impl_declarations_;
|
||||
}
|
||||
auto impls() -> llvm::ArrayRef<Nonnull<ImplDeclaration*>> { return impls_; }
|
||||
|
||||
private:
|
||||
std::vector<Nonnull<ImplDeclaration*>> impls_;
|
||||
std::vector<Nonnull<ImplDeclaration*>> impl_declarations_;
|
||||
};
|
||||
|
||||
class AliasDeclaration : public Declaration {
|
||||
|
||||
@@ -398,9 +398,9 @@ WhereClause::~WhereClause() = default;
|
||||
|
||||
void WhereClause::Print(llvm::raw_ostream& out) const {
|
||||
switch (kind()) {
|
||||
case WhereClauseKind::IsWhereClause: {
|
||||
const auto& clause = cast<IsWhereClause>(*this);
|
||||
out << clause.type() << " is " << clause.constraint();
|
||||
case WhereClauseKind::ImplsWhereClause: {
|
||||
const auto& clause = cast<ImplsWhereClause>(*this);
|
||||
out << clause.type() << " impls " << clause.constraint();
|
||||
break;
|
||||
}
|
||||
case WhereClauseKind::EqualsWhereClause: {
|
||||
|
||||
+15
-11
@@ -224,8 +224,8 @@ class IdentifierExpression : public Expression {
|
||||
// `A`, but with type `type`.
|
||||
//
|
||||
// In a `where` binding, the type of `.Self` is the constraint preceding the
|
||||
// `where` keyword. For example, in `Foo where .Result is Bar(.Self)`, the type
|
||||
// of `.Self` is `Foo`.
|
||||
// `where` keyword. For example, in `Foo where .Result impls Bar(.Self)`, the
|
||||
// type of `.Self` is `Foo`.
|
||||
class DotSelfExpression : public Expression {
|
||||
public:
|
||||
explicit DotSelfExpression(SourceLocation source_loc)
|
||||
@@ -747,7 +747,9 @@ class CallExpression : public Expression {
|
||||
// Maps each of `function`'s impl bindings to a witness.
|
||||
// Should not be called before typechecking, or if `function` is not
|
||||
// a generic function.
|
||||
auto impls() const -> const ImplWitnessMap& { return bindings_.witnesses(); }
|
||||
auto witnesses() const -> const ImplWitnessMap& {
|
||||
return bindings_.witnesses();
|
||||
}
|
||||
|
||||
// Can only be called by type-checking, if a conversion was required.
|
||||
void set_argument(Nonnull<Expression*> argument) { argument_ = argument; }
|
||||
@@ -982,25 +984,27 @@ class WhereClause : public AstNode {
|
||||
: AstNode(context, other) {}
|
||||
};
|
||||
|
||||
// An `is` where clause.
|
||||
// An `impls` where clause.
|
||||
//
|
||||
// For example, `ConstraintA where .Type is ConstraintB` requires that the
|
||||
// For example, `ConstraintA where .Type impls ConstraintB` requires that the
|
||||
// associated type `.Type` implements the constraint `ConstraintB`.
|
||||
class IsWhereClause : public WhereClause {
|
||||
class ImplsWhereClause : public WhereClause {
|
||||
public:
|
||||
explicit IsWhereClause(SourceLocation source_loc, Nonnull<Expression*> type,
|
||||
Nonnull<Expression*> constraint)
|
||||
: WhereClause(WhereClauseKind::IsWhereClause, source_loc),
|
||||
explicit ImplsWhereClause(SourceLocation source_loc,
|
||||
Nonnull<Expression*> type,
|
||||
Nonnull<Expression*> constraint)
|
||||
: WhereClause(WhereClauseKind::ImplsWhereClause, source_loc),
|
||||
type_(type),
|
||||
constraint_(constraint) {}
|
||||
|
||||
explicit IsWhereClause(CloneContext& context, const IsWhereClause& other)
|
||||
explicit ImplsWhereClause(CloneContext& context,
|
||||
const ImplsWhereClause& other)
|
||||
: WhereClause(context, other),
|
||||
type_(context.Clone(other.type_)),
|
||||
constraint_(context.Clone(other.constraint_)) {}
|
||||
|
||||
static auto classof(const AstNode* node) {
|
||||
return InheritsFromIsWhereClause(node->kind());
|
||||
return InheritsFromImplsWhereClause(node->kind());
|
||||
}
|
||||
|
||||
auto type() const -> const Expression& { return *type_; }
|
||||
|
||||
@@ -23,7 +23,7 @@ class GenericBinding;
|
||||
// (`BindingPattern`) there is no explicit syntax that corresponds to
|
||||
// an `ImplBinding`, so they are not created during parsing. Instances
|
||||
// of `ImplBinding` are created during type checking, when processing
|
||||
// a type parameter (a `GenericBinding`), or an `is` requirement in
|
||||
// a type parameter (a `GenericBinding`), or an `impls` requirement in
|
||||
// a `where` clause.
|
||||
class ImplBinding : public AstNode {
|
||||
public:
|
||||
|
||||
@@ -597,10 +597,10 @@ void Value::Print(llvm::raw_ostream& out) const {
|
||||
out << "." << *GetName(rewrite.constant->constant())
|
||||
<< ") = " << *rewrite.unconverted_replacement;
|
||||
}
|
||||
for (const ImplConstraint& impl : constraint.impl_constraints()) {
|
||||
for (const ImplsConstraint& impl : constraint.impls_constraints()) {
|
||||
// TODO: Skip cases where `impl.type` is `.Self` and the interface is
|
||||
// in `lookup_contexts()`.
|
||||
out << sep << *impl.type << " is " << *impl.interface;
|
||||
out << sep << *impl.type << " impls " << *impl.interface;
|
||||
}
|
||||
for (const EqualityConstraint& equality :
|
||||
constraint.equality_constraints()) {
|
||||
@@ -809,17 +809,17 @@ auto TypeEqual(Nonnull<const Value*> t1, Nonnull<const Value*> t2,
|
||||
case Value::Kind::ConstraintType: {
|
||||
const auto& constraint1 = cast<ConstraintType>(*t1);
|
||||
const auto& constraint2 = cast<ConstraintType>(*t2);
|
||||
if (constraint1.impl_constraints().size() !=
|
||||
constraint2.impl_constraints().size() ||
|
||||
if (constraint1.impls_constraints().size() !=
|
||||
constraint2.impls_constraints().size() ||
|
||||
constraint1.equality_constraints().size() !=
|
||||
constraint2.equality_constraints().size() ||
|
||||
constraint1.lookup_contexts().size() !=
|
||||
constraint2.lookup_contexts().size()) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < constraint1.impl_constraints().size(); ++i) {
|
||||
const auto& impl1 = constraint1.impl_constraints()[i];
|
||||
const auto& impl2 = constraint2.impl_constraints()[i];
|
||||
for (size_t i = 0; i < constraint1.impls_constraints().size(); ++i) {
|
||||
const auto& impl1 = constraint1.impls_constraints()[i];
|
||||
const auto& impl2 = constraint2.impls_constraints()[i];
|
||||
if (!TypeEqual(impl1.type, impl2.type, equality_ctx) ||
|
||||
!TypeEqual(impl1.interface, impl2.interface, equality_ctx)) {
|
||||
return false;
|
||||
|
||||
+12
-12
@@ -663,7 +663,7 @@ class FunctionType : public Value {
|
||||
-> llvm::ArrayRef<Nonnull<const GenericBinding*>> {
|
||||
return deduced_bindings_;
|
||||
}
|
||||
// The bindings for the witness tables (impls) required by the
|
||||
// The bindings for the impl witness tables required by the
|
||||
// bounds on the type parameters of the generic function.
|
||||
auto impl_bindings() const -> llvm::ArrayRef<Nonnull<const ImplBinding*>> {
|
||||
return impl_bindings_;
|
||||
@@ -927,7 +927,7 @@ class NamedConstraintType : public Value {
|
||||
};
|
||||
|
||||
// A constraint that requires implementation of an interface.
|
||||
struct ImplConstraint {
|
||||
struct ImplsConstraint {
|
||||
template <typename F>
|
||||
auto Decompose(F f) const {
|
||||
return f(type, interface);
|
||||
@@ -1037,14 +1037,14 @@ class ConstraintType : public Value {
|
||||
public:
|
||||
explicit ConstraintType(
|
||||
Nonnull<const GenericBinding*> self_binding,
|
||||
std::vector<ImplConstraint> impl_constraints,
|
||||
std::vector<ImplsConstraint> impls_constraints,
|
||||
std::vector<IntrinsicConstraint> intrinsic_constraints,
|
||||
std::vector<EqualityConstraint> equality_constraints,
|
||||
std::vector<RewriteConstraint> rewrite_constraints,
|
||||
std::vector<LookupContext> lookup_contexts)
|
||||
: Value(Kind::ConstraintType),
|
||||
self_binding_(self_binding),
|
||||
impl_constraints_(std::move(impl_constraints)),
|
||||
impls_constraints_(std::move(impls_constraints)),
|
||||
intrinsic_constraints_(std::move(intrinsic_constraints)),
|
||||
equality_constraints_(std::move(equality_constraints)),
|
||||
rewrite_constraints_(std::move(rewrite_constraints)),
|
||||
@@ -1056,7 +1056,7 @@ class ConstraintType : public Value {
|
||||
|
||||
template <typename F>
|
||||
auto Decompose(F f) const {
|
||||
return f(self_binding_, impl_constraints_, intrinsic_constraints_,
|
||||
return f(self_binding_, impls_constraints_, intrinsic_constraints_,
|
||||
equality_constraints_, rewrite_constraints_, lookup_contexts_);
|
||||
}
|
||||
|
||||
@@ -1064,8 +1064,8 @@ class ConstraintType : public Value {
|
||||
return self_binding_;
|
||||
}
|
||||
|
||||
auto impl_constraints() const -> llvm::ArrayRef<ImplConstraint> {
|
||||
return impl_constraints_;
|
||||
auto impls_constraints() const -> llvm::ArrayRef<ImplsConstraint> {
|
||||
return impls_constraints_;
|
||||
}
|
||||
|
||||
auto intrinsic_constraints() const -> llvm::ArrayRef<IntrinsicConstraint> {
|
||||
@@ -1097,7 +1097,7 @@ class ConstraintType : public Value {
|
||||
|
||||
private:
|
||||
Nonnull<const GenericBinding*> self_binding_;
|
||||
std::vector<ImplConstraint> impl_constraints_;
|
||||
std::vector<ImplsConstraint> impls_constraints_;
|
||||
std::vector<IntrinsicConstraint> intrinsic_constraints_;
|
||||
std::vector<EqualityConstraint> equality_constraints_;
|
||||
std::vector<RewriteConstraint> rewrite_constraints_;
|
||||
@@ -1175,7 +1175,7 @@ class BindingWitness : public Witness {
|
||||
};
|
||||
|
||||
// A witness for a constraint type, expressed as a tuple of witnesses for the
|
||||
// individual impl constraints in the constraint type.
|
||||
// individual impls constraints in the constraint type.
|
||||
class ConstraintWitness : public Witness {
|
||||
public:
|
||||
explicit ConstraintWitness(std::vector<Nonnull<const Witness*>> witnesses)
|
||||
@@ -1198,11 +1198,11 @@ class ConstraintWitness : public Witness {
|
||||
std::vector<Nonnull<const Witness*>> witnesses_;
|
||||
};
|
||||
|
||||
// A witness for an impl constraint in a constraint type, expressed in terms of
|
||||
// A witness for an impls constraint in a constraint type, expressed in terms of
|
||||
// a symbolic witness for the constraint type.
|
||||
class ConstraintImplWitness : public Witness {
|
||||
public:
|
||||
// Make a witness for the given impl_constraint of the given `ConstraintType`
|
||||
// Make a witness for the given impls_constraint of the given `ConstraintType`
|
||||
// witness. If we're indexing into a known tuple of witnesses, pull out the
|
||||
// element.
|
||||
static auto Make(Nonnull<Arena*> arena, Nonnull<const Witness*> witness,
|
||||
@@ -1239,7 +1239,7 @@ class ConstraintImplWitness : public Witness {
|
||||
return constraint_witness_;
|
||||
}
|
||||
|
||||
// Get the index of the impl constraint within the constraint type.
|
||||
// Get the index of the impls constraint within the constraint type.
|
||||
auto index() const -> int { return index_; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -70,8 +70,8 @@ __match_first {
|
||||
}
|
||||
|
||||
// A tuple explicitly converts to another tuple if all its elements do. Note
|
||||
// that this fully overlaps with the previous set of impls for the case where
|
||||
// an implicit conversion is possible.
|
||||
// that this fully overlaps with the previous set of impl declarations for
|
||||
// the case where an implicit conversion is possible.
|
||||
impl forall [U1:! type, T1:! As(U1)]
|
||||
(T1,) as As((U1,)) {
|
||||
fn Convert[self: Self]() -> (U1,) {
|
||||
@@ -389,7 +389,7 @@ constraint Mod {
|
||||
extends ModWith(Self) where .Result = Self;
|
||||
}
|
||||
|
||||
// Note, these impls use the builtin addition for i32.
|
||||
// Note, these impl declarations use the builtin addition for i32.
|
||||
external impl i32 as Negate where .Result = i32 {
|
||||
fn Op[self: i32]() -> i32 { return -self; }
|
||||
}
|
||||
@@ -571,70 +571,70 @@ impl forall [T:! type, U:! ImplicitAs(T)]
|
||||
}
|
||||
|
||||
// TODO: Should `AddWith(U) & AssignWith(.Self.(AddWith(U).Result))` work?
|
||||
impl forall [U:! type, T:! AddWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
impl forall [U:! type, T:! AddWith(U) where .Self impls AssignWith(.Self.Result)]
|
||||
T as AddAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self + other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! SubWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
impl forall [U:! type, T:! SubWith(U) where .Self impls AssignWith(.Self.Result)]
|
||||
T as SubAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self - other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! MulWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
impl forall [U:! type, T:! MulWith(U) where .Self impls AssignWith(.Self.Result)]
|
||||
T as MulAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self * other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! DivWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
impl forall [U:! type, T:! DivWith(U) where .Self impls AssignWith(.Self.Result)]
|
||||
T as DivAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self / other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! ModWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
impl forall [U:! type, T:! ModWith(U) where .Self impls AssignWith(.Self.Result)]
|
||||
T as ModAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self % other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! BitAndWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
impl forall [U:! type, T:! BitAndWith(U) where .Self impls AssignWith(.Self.Result)]
|
||||
T as BitAndAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self & other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! BitOrWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
impl forall [U:! type, T:! BitOrWith(U) where .Self impls AssignWith(.Self.Result)]
|
||||
T as BitOrAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self | other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! BitXorWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
impl forall [U:! type, T:! BitXorWith(U) where .Self impls AssignWith(.Self.Result)]
|
||||
T as BitXorAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self ^ other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! LeftShiftWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
impl forall [U:! type, T:! LeftShiftWith(U) where .Self impls AssignWith(.Self.Result)]
|
||||
T as LeftShiftAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self << other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! RightShiftWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
impl forall [U:! type, T:! RightShiftWith(U) where .Self impls AssignWith(.Self.Result)]
|
||||
T as RightShiftAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self >> other;
|
||||
|
||||
@@ -256,12 +256,12 @@ static auto ExpressionToProto(const Expression& expression)
|
||||
for (const WhereClause* where : where.clauses()) {
|
||||
Fuzzing::WhereClause clause_proto;
|
||||
switch (where->kind()) {
|
||||
case WhereClauseKind::IsWhereClause: {
|
||||
auto* is_proto = clause_proto.mutable_is();
|
||||
*is_proto->mutable_type() =
|
||||
ExpressionToProto(cast<IsWhereClause>(where)->type());
|
||||
*is_proto->mutable_constraint() =
|
||||
ExpressionToProto(cast<IsWhereClause>(where)->constraint());
|
||||
case WhereClauseKind::ImplsWhereClause: {
|
||||
auto* impls_proto = clause_proto.mutable_impls();
|
||||
*impls_proto->mutable_type() =
|
||||
ExpressionToProto(cast<ImplsWhereClause>(where)->type());
|
||||
*impls_proto->mutable_constraint() =
|
||||
ExpressionToProto(cast<ImplsWhereClause>(where)->constraint());
|
||||
break;
|
||||
}
|
||||
case WhereClauseKind::EqualsWhereClause: {
|
||||
@@ -845,8 +845,8 @@ static auto DeclarationToProto(const Declaration& declaration)
|
||||
case DeclarationKind::MatchFirstDeclaration: {
|
||||
const auto& match_first = cast<MatchFirstDeclaration>(declaration);
|
||||
auto* match_first_proto = declaration_proto.mutable_match_first();
|
||||
for (const auto* impl : match_first.impls()) {
|
||||
*match_first_proto->add_impls() = DeclarationToProto(*impl);
|
||||
for (const auto* impl : match_first.impl_declarations()) {
|
||||
*match_first_proto->add_impl_declarations() = DeclarationToProto(*impl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+2
-1
@@ -32,7 +32,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
clauses {
|
||||
is {
|
||||
impls {
|
||||
type {
|
||||
int_type_literal {
|
||||
}
|
||||
@@ -76,3 +76,4 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ compilation_unit {
|
||||
}
|
||||
declarations {
|
||||
match_first {
|
||||
impls {
|
||||
impl_declarations {
|
||||
impl {
|
||||
kind: ExternalImpl
|
||||
impl_type {
|
||||
@@ -69,7 +69,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
}
|
||||
impls {
|
||||
impl_declarations {
|
||||
impl {
|
||||
kind: ExternalImpl
|
||||
impl_type {
|
||||
+2
-1
@@ -82,7 +82,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
clauses {
|
||||
is {
|
||||
impls {
|
||||
type {
|
||||
int_type_literal {
|
||||
}
|
||||
@@ -239,3 +239,4 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -66,7 +66,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
clauses {
|
||||
is {
|
||||
impls {
|
||||
type {
|
||||
designator {
|
||||
name: "Self"
|
||||
@@ -393,3 +393,4 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -148,7 +148,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
clauses {
|
||||
is {
|
||||
impls {
|
||||
type {
|
||||
designator {
|
||||
name: "Self"
|
||||
@@ -323,3 +323,4 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -23,7 +23,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
clauses {
|
||||
is {
|
||||
impls {
|
||||
type {
|
||||
int_literal {
|
||||
value: 4
|
||||
@@ -68,3 +68,4 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -75,7 +75,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
clauses {
|
||||
is {
|
||||
impls {
|
||||
type {
|
||||
int_type_literal {
|
||||
}
|
||||
@@ -300,3 +300,4 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -49,7 +49,7 @@ compilation_unit {
|
||||
}
|
||||
declarations {
|
||||
match_first {
|
||||
impls {
|
||||
impl_declarations {
|
||||
impl {
|
||||
kind: ExternalImpl
|
||||
impl_type {
|
||||
@@ -91,7 +91,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
}
|
||||
impls {
|
||||
impl_declarations {
|
||||
impl {
|
||||
kind: ExternalImpl
|
||||
impl_type {
|
||||
@@ -133,7 +133,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
}
|
||||
impls {
|
||||
impl_declarations {
|
||||
impl {
|
||||
kind: ExternalImpl
|
||||
impl_type {
|
||||
@@ -175,7 +175,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
}
|
||||
impls {
|
||||
impl_declarations {
|
||||
impl {
|
||||
kind: ExternalImpl
|
||||
impl_type {
|
||||
+6
-5
@@ -162,7 +162,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
clauses {
|
||||
is {
|
||||
impls {
|
||||
type {
|
||||
designator {
|
||||
name: "Self"
|
||||
@@ -204,7 +204,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
clauses {
|
||||
is {
|
||||
impls {
|
||||
type {
|
||||
designator {
|
||||
name: "Self"
|
||||
@@ -246,7 +246,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
clauses {
|
||||
is {
|
||||
impls {
|
||||
type {
|
||||
designator {
|
||||
name: "Self"
|
||||
@@ -288,7 +288,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
clauses {
|
||||
is {
|
||||
impls {
|
||||
type {
|
||||
designator {
|
||||
name: "Self"
|
||||
@@ -330,7 +330,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
clauses {
|
||||
is {
|
||||
impls {
|
||||
type {
|
||||
designator {
|
||||
name: "Self"
|
||||
@@ -890,3 +890,4 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -23,7 +23,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
clauses {
|
||||
is {
|
||||
impls {
|
||||
type {
|
||||
int_type_literal {
|
||||
}
|
||||
@@ -66,3 +66,4 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -23,7 +23,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
clauses {
|
||||
is {
|
||||
impls {
|
||||
type {
|
||||
int_type_literal {
|
||||
}
|
||||
@@ -67,3 +67,4 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -208,7 +208,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
clauses {
|
||||
is {
|
||||
impls {
|
||||
type {
|
||||
designator {
|
||||
name: "Self"
|
||||
@@ -370,3 +370,4 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -52,7 +52,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
clauses {
|
||||
is {
|
||||
impls {
|
||||
type {
|
||||
designator {
|
||||
name: "Self"
|
||||
@@ -245,3 +245,4 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -167,7 +167,7 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
clauses {
|
||||
is {
|
||||
impls {
|
||||
type {
|
||||
designator {
|
||||
name: "Self"
|
||||
@@ -476,3 +476,4 @@ compilation_unit {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ void ImplScope::Add(Nonnull<const Value*> iface,
|
||||
CARBON_CHECK(!sort_key)
|
||||
<< "should only be given a sort key for an impl of an interface";
|
||||
// The caller should have substituted `.Self` for `type` already.
|
||||
Add(constraint->impl_constraints(), deduced, impl_bindings, witness,
|
||||
Add(constraint->impls_constraints(), deduced, impl_bindings, witness,
|
||||
type_checker);
|
||||
// A parameterized impl declaration doesn't contribute any equality
|
||||
// constraints to the scope. Instead, we'll resolve the equality
|
||||
@@ -46,30 +46,32 @@ void ImplScope::Add(Nonnull<const Value*> iface,
|
||||
return;
|
||||
}
|
||||
|
||||
Impl new_impl = {.interface = cast<InterfaceType>(iface),
|
||||
.deduced = deduced,
|
||||
.type = type,
|
||||
.impl_bindings = impl_bindings,
|
||||
.witness = witness,
|
||||
.sort_key = std::move(sort_key)};
|
||||
ImplFact new_impl = {.interface = cast<InterfaceType>(iface),
|
||||
.deduced = deduced,
|
||||
.type = type,
|
||||
.impl_bindings = impl_bindings,
|
||||
.witness = witness,
|
||||
.sort_key = std::move(sort_key)};
|
||||
|
||||
// Find the first impl that's more specific than this one, and place this
|
||||
// impl right before it. This keeps the impls with the same type structure
|
||||
// sorted in lexical order, which is important for `match_first` semantics.
|
||||
auto insert_pos = std::upper_bound(
|
||||
impls_.begin(), impls_.end(), new_impl,
|
||||
[](const Impl& a, const Impl& b) { return a.sort_key < b.sort_key; });
|
||||
auto insert_pos =
|
||||
std::upper_bound(impl_facts_.begin(), impl_facts_.end(), new_impl,
|
||||
[](const ImplFact& a, const ImplFact& b) {
|
||||
return a.sort_key < b.sort_key;
|
||||
});
|
||||
|
||||
impls_.insert(insert_pos, std::move(new_impl));
|
||||
impl_facts_.insert(insert_pos, std::move(new_impl));
|
||||
}
|
||||
|
||||
void ImplScope::Add(llvm::ArrayRef<ImplConstraint> impls,
|
||||
void ImplScope::Add(llvm::ArrayRef<ImplsConstraint> impls_constraints,
|
||||
llvm::ArrayRef<Nonnull<const GenericBinding*>> deduced,
|
||||
llvm::ArrayRef<Nonnull<const ImplBinding*>> impl_bindings,
|
||||
Nonnull<const Witness*> witness,
|
||||
const TypeChecker& type_checker) {
|
||||
for (size_t i = 0; i != impls.size(); ++i) {
|
||||
ImplConstraint impl = impls[i];
|
||||
for (size_t i = 0; i != impls_constraints.size(); ++i) {
|
||||
ImplsConstraint impl = impls_constraints[i];
|
||||
Add(impl.interface, deduced, impl.type, impl_bindings,
|
||||
type_checker.MakeConstraintWitnessAccess(witness, i), type_checker);
|
||||
}
|
||||
@@ -129,18 +131,18 @@ auto ImplScope::TryResolve(Nonnull<const Value*> constraint_type,
|
||||
}
|
||||
if (const auto* constraint = dyn_cast<ConstraintType>(constraint_type)) {
|
||||
std::vector<Nonnull<const Witness*>> witnesses;
|
||||
for (auto impl : constraint->impl_constraints()) {
|
||||
// Note that later impl constraints can refer to earlier impl constraints
|
||||
// via impl bindings. For example, in
|
||||
// `C where .Self.AssocType is D`,
|
||||
// ... the `.Self.AssocType is D` constraint refers to the `.Self is C`
|
||||
// constraint when naming `AssocType`. So incrementally build up a
|
||||
// partial constraint witness as we go.
|
||||
for (auto impl : constraint->impls_constraints()) {
|
||||
// Note that later impls constraints can refer to earlier impls
|
||||
// constraints via impl bindings. For example, in
|
||||
// `C where .Self.AssocType impls D`,
|
||||
// ... the `.Self.AssocType impls D` constraint refers to the
|
||||
// `.Self impls C` constraint when naming `AssocType`. So incrementally
|
||||
// build up a partial constraint witness as we go.
|
||||
std::optional<Nonnull<const Witness*>> witness;
|
||||
if (constraint->self_binding()->impl_binding()) {
|
||||
// Note, this is a partial impl binding covering only the impl
|
||||
// constraints that we've already seen. Earlier impl constraints should
|
||||
// not be able to refer to impl bindings for later impl constraints.
|
||||
// constraints that we've already seen. Earlier impls constraints should
|
||||
// not be able to refer to impl bindings for later impls constraints.
|
||||
witness = type_checker.MakeConstraintWitness(witnesses);
|
||||
}
|
||||
Bindings local_bindings = bindings;
|
||||
@@ -382,9 +384,9 @@ auto ImplScope::TryResolveInterfaceHere(
|
||||
const TypeChecker& type_checker) const
|
||||
-> ErrorOr<std::optional<ResolveResult>> {
|
||||
std::optional<ResolveResult> result = std::nullopt;
|
||||
for (const Impl& impl : impls_) {
|
||||
for (const ImplFact& impl : impl_facts_) {
|
||||
// If we've passed the final impl with a sort key matching our best impl,
|
||||
// all further impls are worse and don't need to be checked.
|
||||
// all further are worse and don't need to be checked.
|
||||
if (result && result->impl->sort_key < impl.sort_key) {
|
||||
break;
|
||||
}
|
||||
@@ -417,9 +419,9 @@ auto ImplScope::TryResolveInterfaceHere(
|
||||
|
||||
// TODO: Add indentation when printing the parents.
|
||||
void ImplScope::Print(llvm::raw_ostream& out) const {
|
||||
out << "impls: ";
|
||||
out << "impl declarations: ";
|
||||
llvm::ListSeparator sep;
|
||||
for (const Impl& impl : impls_) {
|
||||
for (const ImplFact& impl : impl_facts_) {
|
||||
out << sep << *(impl.type) << " as " << *(impl.interface);
|
||||
if (impl.sort_key) {
|
||||
out << " " << *impl.sort_key;
|
||||
|
||||
@@ -16,15 +16,15 @@ class TypeChecker;
|
||||
// The `ImplScope` class is responsible for mapping a type and
|
||||
// interface to the location of the witness table for the `impl` for
|
||||
// that type and interface. A scope may have parent scopes, whose
|
||||
// impls will also be visible in the child scope.
|
||||
// implementations will also be visible in the child scope.
|
||||
//
|
||||
// There is typically one instance of `ImplScope` class per scope
|
||||
// because the impls that are visible for a given type and interface
|
||||
// can vary from scope to scope. For example, consider the `bar` and
|
||||
// `baz` methods in the following class C and nested class D.
|
||||
// because the implementationss that are visible for a given type and
|
||||
// interface can vary from scope to scope. For example, consider the
|
||||
// `bar` and `baz` methods in the following class C and nested class D.
|
||||
//
|
||||
// class C(U:! type, T:! type) {
|
||||
// class D(V:! type where U is Fooable(T)) {
|
||||
// class D(V:! type where U impls Fooable(T)) {
|
||||
// fn bar[self: Self](x: U, y : T) -> T{
|
||||
// return x.foo(y)
|
||||
// }
|
||||
@@ -43,7 +43,7 @@ class TypeChecker;
|
||||
// scope.
|
||||
class ImplScope {
|
||||
public:
|
||||
// The `Impl` struct is a key-value pair where the key is the
|
||||
// The `ImplFact` struct is a key-value pair where the key is the
|
||||
// combination of a type and an interface, e.g., `List` and `Container`,
|
||||
// and the value is the result of statically resolving to the `impl`
|
||||
// for `List` as `Container`, which is an `Expression` that produces
|
||||
@@ -54,7 +54,7 @@ class ImplScope {
|
||||
// later are impl bindings, that is, parameters for witnesses. In this case,
|
||||
// `sort_key` indicates the order in which this impl should be considered
|
||||
// relative to other matching impls.
|
||||
struct Impl {
|
||||
struct ImplFact {
|
||||
Nonnull<const InterfaceType*> interface;
|
||||
std::vector<Nonnull<const GenericBinding*>> deduced;
|
||||
Nonnull<const Value*> type;
|
||||
@@ -66,7 +66,7 @@ class ImplScope {
|
||||
// Internal type used to represent the result of resolving a lookup in a
|
||||
// particular impl scope.
|
||||
struct ResolveResult {
|
||||
Nonnull<const Impl*> impl;
|
||||
Nonnull<const ImplFact*> impl;
|
||||
Nonnull<const Witness*> witness;
|
||||
};
|
||||
|
||||
@@ -89,10 +89,10 @@ class ImplScope {
|
||||
llvm::ArrayRef<Nonnull<const ImplBinding*>> impl_bindings,
|
||||
Nonnull<const Witness*> witness, const TypeChecker& type_checker,
|
||||
std::optional<TypeStructureSortKey> sort_key = std::nullopt);
|
||||
// Adds a list of impl constraints from a constraint type into scope. Any
|
||||
// Adds a list of impls constraints from a constraint type into scope. Any
|
||||
// references to `.Self` are expected to have already been substituted for
|
||||
// the type implementing the constraint.
|
||||
void Add(llvm::ArrayRef<ImplConstraint> impls,
|
||||
void Add(llvm::ArrayRef<ImplsConstraint> impls_constraints,
|
||||
llvm::ArrayRef<Nonnull<const GenericBinding*>> deduced,
|
||||
llvm::ArrayRef<Nonnull<const ImplBinding*>> impl_bindings,
|
||||
Nonnull<const Witness*> witness, const TypeChecker& type_checker);
|
||||
@@ -176,7 +176,7 @@ class ImplScope {
|
||||
const TypeChecker& type_checker) const
|
||||
-> ErrorOr<std::optional<ResolveResult>>;
|
||||
|
||||
std::vector<Impl> impls_;
|
||||
std::vector<ImplFact> impl_facts_;
|
||||
std::vector<Nonnull<const EqualityConstraint*>> equalities_;
|
||||
std::optional<Nonnull<const ImplScope*>> parent_scope_;
|
||||
};
|
||||
|
||||
@@ -1355,7 +1355,7 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
|
||||
}
|
||||
case ExpressionKind::CallExpression: {
|
||||
const auto& call = cast<CallExpression>(exp);
|
||||
unsigned int num_impls = call.impls().size();
|
||||
unsigned int num_witnesses = call.witnesses().size();
|
||||
if (act.pos() == 0) {
|
||||
// { {e1(e2) :: C, E, F} :: S, H}
|
||||
// -> { {e1 :: [](e2) :: C, E, F} :: S, H}
|
||||
@@ -1366,31 +1366,32 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
|
||||
// -> { { e :: v([]) :: C, E, F} :: S, H}
|
||||
return todo_.Spawn(
|
||||
std::make_unique<ExpressionAction>(&call.argument()));
|
||||
} else if (num_impls > 0 && act.pos() < 2 + static_cast<int>(num_impls)) {
|
||||
auto iter = call.impls().begin();
|
||||
} else if (num_witnesses > 0 &&
|
||||
act.pos() < 2 + static_cast<int>(num_witnesses)) {
|
||||
auto iter = call.witnesses().begin();
|
||||
std::advance(iter, act.pos() - 2);
|
||||
return todo_.Spawn(
|
||||
std::make_unique<WitnessAction>(cast<Witness>(iter->second)));
|
||||
} else if (act.pos() == 2 + static_cast<int>(num_impls)) {
|
||||
} else if (act.pos() == 2 + static_cast<int>(num_witnesses)) {
|
||||
// { { v2 :: v1([]) :: C, E, F} :: S, H}
|
||||
// -> { {C',E',F'} :: {C, E, F} :: S, H}
|
||||
ImplWitnessMap witnesses;
|
||||
if (num_impls > 0) {
|
||||
if (num_witnesses > 0) {
|
||||
int i = 2;
|
||||
for (const auto& [impl_bind, impl_exp] : call.impls()) {
|
||||
for (const auto& [impl_bind, impl_exp] : call.witnesses()) {
|
||||
witnesses[impl_bind] = act.results()[i];
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return CallFunction(call, act.results()[0], act.results()[1],
|
||||
std::move(witnesses));
|
||||
} else if (act.pos() == 3 + static_cast<int>(num_impls)) {
|
||||
if (act.results().size() < 3 + num_impls) {
|
||||
} else if (act.pos() == 3 + static_cast<int>(num_witnesses)) {
|
||||
if (act.results().size() < 3 + num_witnesses) {
|
||||
// Control fell through without explicit return.
|
||||
return todo_.FinishAction(TupleValue::Empty());
|
||||
} else {
|
||||
return todo_.FinishAction(
|
||||
act.results()[2 + static_cast<int>(num_impls)]);
|
||||
act.results()[2 + static_cast<int>(num_witnesses)]);
|
||||
}
|
||||
} else {
|
||||
CARBON_FATAL() << "in StepExp with Call pos " << act.pos();
|
||||
@@ -1521,7 +1522,7 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
|
||||
.kind = IntrinsicConstraint::ImplicitAs,
|
||||
.arguments = args};
|
||||
auto* result = arena_->New<ConstraintType>(
|
||||
self_binding, std::vector<ImplConstraint>{},
|
||||
self_binding, std::vector<ImplsConstraint>{},
|
||||
std::vector<IntrinsicConstraint>{std::move(constraint)},
|
||||
std::vector<EqualityConstraint>{},
|
||||
std::vector<RewriteConstraint>{}, std::vector<LookupContext>{});
|
||||
|
||||
@@ -105,7 +105,7 @@ auto MatchingImplSet::GetLabelForDeclaration(const Declaration& declaration)
|
||||
}
|
||||
|
||||
MatchingImplSet::Match::Match(Nonnull<MatchingImplSet*> parent,
|
||||
Nonnull<const ImplScope::Impl*> impl,
|
||||
Nonnull<const ImplScope::ImplFact*> impl,
|
||||
Nonnull<const Value*> type,
|
||||
Nonnull<const Value*> interface)
|
||||
: parent_(parent), impl_(impl), type_(type), interface_(interface) {
|
||||
|
||||
@@ -44,7 +44,7 @@ class MatchingImplSet {
|
||||
class Match {
|
||||
public:
|
||||
explicit Match(Nonnull<MatchingImplSet*> parent,
|
||||
Nonnull<const ImplScope::Impl*> impl,
|
||||
Nonnull<const ImplScope::ImplFact*> impl,
|
||||
Nonnull<const Value*> type, Nonnull<const Value*> interface);
|
||||
~Match();
|
||||
|
||||
@@ -63,7 +63,7 @@ class MatchingImplSet {
|
||||
// The set that this match is part of.
|
||||
Nonnull<MatchingImplSet*> parent_;
|
||||
// The `impl` that is being matched against.
|
||||
Nonnull<const ImplScope::Impl*> impl_;
|
||||
Nonnull<const ImplScope::ImplFact*> impl_;
|
||||
// The type that is being matched against the impl.
|
||||
Nonnull<const Value*> type_;
|
||||
// The interface that is being matched against the impl.
|
||||
|
||||
@@ -181,7 +181,7 @@ auto ResolveControlFlow(Nonnull<Declaration*> declaration) -> ErrorOr<Success> {
|
||||
}
|
||||
case DeclarationKind::MatchFirstDeclaration: {
|
||||
auto& match_first_decl = cast<MatchFirstDeclaration>(*declaration);
|
||||
for (Nonnull<Declaration*> impl : match_first_decl.impls()) {
|
||||
for (Nonnull<Declaration*> impl : match_first_decl.impl_declarations()) {
|
||||
CARBON_RETURN_IF_ERROR(ResolveControlFlow(impl));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -413,11 +413,12 @@ auto NameResolver::ResolveNames(WhereClause& clause,
|
||||
const StaticScope& enclosing_scope)
|
||||
-> ErrorOr<Success> {
|
||||
switch (clause.kind()) {
|
||||
case WhereClauseKind::IsWhereClause: {
|
||||
auto& is_clause = cast<IsWhereClause>(clause);
|
||||
CARBON_RETURN_IF_ERROR(ResolveNames(is_clause.type(), enclosing_scope));
|
||||
case WhereClauseKind::ImplsWhereClause: {
|
||||
auto& impls_clause = cast<ImplsWhereClause>(clause);
|
||||
CARBON_RETURN_IF_ERROR(
|
||||
ResolveNames(is_clause.constraint(), enclosing_scope));
|
||||
ResolveNames(impls_clause.type(), enclosing_scope));
|
||||
CARBON_RETURN_IF_ERROR(
|
||||
ResolveNames(impls_clause.constraint(), enclosing_scope));
|
||||
break;
|
||||
}
|
||||
case WhereClauseKind::EqualsWhereClause: {
|
||||
@@ -697,7 +698,8 @@ auto NameResolver::ResolveNames(Declaration& declaration,
|
||||
}
|
||||
case DeclarationKind::MatchFirstDeclaration: {
|
||||
// A `match_first` declaration does not introduce a scope.
|
||||
for (auto* impl : cast<MatchFirstDeclaration>(declaration).impls()) {
|
||||
for (auto* impl :
|
||||
cast<MatchFirstDeclaration>(declaration).impl_declarations()) {
|
||||
CARBON_RETURN_IF_ERROR(ResolveNames(*impl, enclosing_scope, bodies));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -526,7 +526,7 @@ auto TypeChecker::IsImplicitlyConvertible(
|
||||
const ImplScope& impl_scope, bool allow_user_defined_conversions) const
|
||||
-> ErrorOr<bool> {
|
||||
// Check for an exact match or for an implicit conversion.
|
||||
// TODO: `impl`s of `ImplicitAs` should be provided to cover these
|
||||
// TODO: `impl` definitions of `ImplicitAs` should be provided to cover these
|
||||
// conversions.
|
||||
CARBON_CHECK(IsConcreteType(source));
|
||||
CARBON_CHECK(IsConcreteType(destination));
|
||||
@@ -1515,18 +1515,18 @@ class TypeChecker::ConstraintTypeBuilder {
|
||||
return cast<Witness>(*impl_binding_->symbolic_identity());
|
||||
}
|
||||
|
||||
// Adds an `impl` constraint -- `T is C` if not already present.
|
||||
// Returns the index of the impl constraint within the self witness.
|
||||
auto AddImplConstraint(ImplConstraint impl) -> int {
|
||||
for (int i = 0; i != static_cast<int>(impl_constraints_.size()); ++i) {
|
||||
ImplConstraint& existing = impl_constraints_[i];
|
||||
if (TypeEqual(existing.type, impl.type, std::nullopt) &&
|
||||
TypeEqual(existing.interface, impl.interface, std::nullopt)) {
|
||||
// Adds an `impls` constraint -- `T impls C` if not already present.
|
||||
// Returns the index of the impls constraint within the self witness.
|
||||
auto AddImplsConstraint(ImplsConstraint impls) -> int {
|
||||
for (int i = 0; i != static_cast<int>(impls_constraints_.size()); ++i) {
|
||||
ImplsConstraint& existing = impls_constraints_[i];
|
||||
if (TypeEqual(existing.type, impls.type, std::nullopt) &&
|
||||
TypeEqual(existing.interface, impls.interface, std::nullopt)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
impl_constraints_.push_back(impl);
|
||||
return impl_constraints_.size() - 1;
|
||||
impls_constraints_.push_back(impls);
|
||||
return impls_constraints_.size() - 1;
|
||||
}
|
||||
|
||||
// Adds an intrinsic constraint, if not already present.
|
||||
@@ -1585,17 +1585,17 @@ class TypeChecker::ConstraintTypeBuilder {
|
||||
// First substitute into the impl bindings to form the full witness for
|
||||
// the constraint type.
|
||||
std::vector<Nonnull<const Witness*>> witnesses;
|
||||
for (const auto& impl_constraint : constraint->impl_constraints()) {
|
||||
for (const auto& impls_constraint : constraint->impls_constraints()) {
|
||||
Bindings local_bindings = bindings;
|
||||
local_bindings.Add(constraint->self_binding(), self,
|
||||
type_checker.MakeConstraintWitness(witnesses));
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
Nonnull<const Value*> type,
|
||||
type_checker.Substitute(local_bindings, impl_constraint.type));
|
||||
type_checker.Substitute(local_bindings, impls_constraint.type));
|
||||
CARBON_ASSIGN_OR_RETURN(const auto* interface,
|
||||
type_checker.SubstituteCast<InterfaceType>(
|
||||
local_bindings, impl_constraint.interface));
|
||||
int index = AddImplConstraint({.type = type, .interface = interface});
|
||||
local_bindings, impls_constraint.interface));
|
||||
int index = AddImplsConstraint({.type = type, .interface = interface});
|
||||
witnesses.push_back(
|
||||
type_checker.MakeConstraintWitnessAccess(self_witness, index));
|
||||
}
|
||||
@@ -1622,8 +1622,8 @@ class TypeChecker::ConstraintTypeBuilder {
|
||||
rewrite_constraint.converted_replacement));
|
||||
|
||||
// Form a symbolic value naming the non-rewritten associated constant.
|
||||
// The impl constraint will always already exist.
|
||||
int index = AddImplConstraint({.type = self, .interface = interface});
|
||||
// The impls constraint will always already exist.
|
||||
int index = AddImplsConstraint({.type = self, .interface = interface});
|
||||
const auto* witness =
|
||||
type_checker.MakeConstraintWitnessAccess(self_witness, index);
|
||||
const auto* constant_value = arena_->New<AssociatedConstant>(
|
||||
@@ -1700,31 +1700,31 @@ class TypeChecker::ConstraintTypeBuilder {
|
||||
friend class ConstraintTypeBuilder;
|
||||
|
||||
private:
|
||||
int num_impls_added = 0;
|
||||
int num_equals_added = 0;
|
||||
int num_impls_constraints_added = 0;
|
||||
int num_equality_constraints_added = 0;
|
||||
};
|
||||
|
||||
// Brings all the constraints accumulated so far into the given impl scope,
|
||||
// as if we built the constraint type and then added it into the scope. If
|
||||
// this will be called more than once, an ImplsInScopeTracker can be provided
|
||||
// to avoid adding the same impls more than once.
|
||||
// Brings all the constraints accumulated so far into the given impl scope, as
|
||||
// if we built the constraint type and then added it into the scope. If this
|
||||
// will be called more than once, an ConstraintssInScopeTracker can be
|
||||
// provided to avoid adding the same implementations more than once.
|
||||
void BringConstraintsIntoScope(const TypeChecker& type_checker,
|
||||
Nonnull<ImplScope*> impl_scope,
|
||||
Nonnull<ConstraintsInScopeTracker*> tracker) {
|
||||
// Figure out which constraints we're going to add.
|
||||
int first_impl_to_add =
|
||||
std::exchange(tracker->num_impls_added, impl_constraints_.size());
|
||||
int first_equal_to_add =
|
||||
std::exchange(tracker->num_equals_added, equality_constraints_.size());
|
||||
auto new_impl_constraints =
|
||||
llvm::ArrayRef<ImplConstraint>(impl_constraints_)
|
||||
.drop_front(first_impl_to_add);
|
||||
int first_impls_constraint_to_add = std::exchange(
|
||||
tracker->num_impls_constraints_added, impls_constraints_.size());
|
||||
int first_equality_constraint_to_add = std::exchange(
|
||||
tracker->num_equality_constraints_added, equality_constraints_.size());
|
||||
auto new_impls_constraints =
|
||||
llvm::ArrayRef<ImplsConstraint>(impls_constraints_)
|
||||
.drop_front(first_impls_constraint_to_add);
|
||||
auto new_equality_constraints =
|
||||
llvm::ArrayRef<EqualityConstraint>(equality_constraints_)
|
||||
.drop_front(first_equal_to_add);
|
||||
.drop_front(first_equality_constraint_to_add);
|
||||
|
||||
// Add all of the new constraints.
|
||||
impl_scope->Add(new_impl_constraints, std::nullopt, std::nullopt,
|
||||
impl_scope->Add(new_impls_constraints, std::nullopt, std::nullopt,
|
||||
GetSelfWitness(), type_checker);
|
||||
for (const auto& equal : new_equality_constraints) {
|
||||
impl_scope->AddEqualityConstraint(arena_->New<EqualityConstraint>(equal));
|
||||
@@ -1751,7 +1751,7 @@ class TypeChecker::ConstraintTypeBuilder {
|
||||
auto Build() && -> Nonnull<const ConstraintType*> {
|
||||
// Create the new type.
|
||||
auto* result = arena_->New<ConstraintType>(
|
||||
self_binding_, std::move(impl_constraints_),
|
||||
self_binding_, std::move(impls_constraints_),
|
||||
std::move(intrinsic_constraints_), std::move(equality_constraints_),
|
||||
std::move(rewrite_constraints_), std::move(lookup_contexts_));
|
||||
// Update the impl binding to denote the constraint type itself.
|
||||
@@ -1912,14 +1912,14 @@ class TypeChecker::ConstraintTypeBuilder {
|
||||
type_checker.RebuildValue(rewrite.unconverted_replacement_type));
|
||||
}
|
||||
|
||||
// Apply rewrites throughout impl constraints.
|
||||
for (auto& impl_constraint : impl_constraints_) {
|
||||
CARBON_ASSIGN_OR_RETURN(impl_constraint.type,
|
||||
type_checker.RebuildValue(impl_constraint.type));
|
||||
// Apply rewrites throughout impls constraints.
|
||||
for (auto& impls_constraint : impls_constraints_) {
|
||||
CARBON_ASSIGN_OR_RETURN(impls_constraint.type,
|
||||
type_checker.RebuildValue(impls_constraint.type));
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
const auto* subst_interface,
|
||||
type_checker.RebuildValue(impl_constraint.interface));
|
||||
impl_constraint.interface = cast<InterfaceType>(subst_interface);
|
||||
type_checker.RebuildValue(impls_constraint.interface));
|
||||
impls_constraint.interface = cast<InterfaceType>(subst_interface);
|
||||
}
|
||||
|
||||
// Apply rewrites throughout intrinsic constraints.
|
||||
@@ -1952,7 +1952,7 @@ class TypeChecker::ConstraintTypeBuilder {
|
||||
Nonnull<Arena*> arena_;
|
||||
Nonnull<GenericBinding*> self_binding_;
|
||||
Nonnull<ImplBinding*> impl_binding_;
|
||||
std::vector<ImplConstraint> impl_constraints_;
|
||||
std::vector<ImplsConstraint> impls_constraints_;
|
||||
std::vector<IntrinsicConstraint> intrinsic_constraints_;
|
||||
std::vector<EqualityConstraint> equality_constraints_;
|
||||
std::vector<RewriteConstraint> rewrite_constraints_;
|
||||
@@ -2274,7 +2274,7 @@ auto TypeChecker::RefineWitness(Nonnull<const Witness*> witness,
|
||||
|
||||
auto TypeChecker::MatchImpl(const InterfaceType& iface,
|
||||
Nonnull<const Value*> impl_type,
|
||||
const ImplScope::Impl& impl,
|
||||
const ImplScope::ImplFact& impl,
|
||||
const ImplScope& impl_scope,
|
||||
SourceLocation source_loc) const
|
||||
-> ErrorOr<std::optional<Nonnull<const Witness*>>> {
|
||||
@@ -2343,9 +2343,9 @@ auto TypeChecker::MatchImpl(const InterfaceType& iface,
|
||||
}
|
||||
|
||||
auto TypeChecker::MakeConstraintWitness(
|
||||
std::vector<Nonnull<const Witness*>> impl_constraint_witnesses) const
|
||||
std::vector<Nonnull<const Witness*>> impls_constraint_witnesses) const
|
||||
-> Nonnull<const Witness*> {
|
||||
return arena_->New<ConstraintWitness>(std::move(impl_constraint_witnesses));
|
||||
return arena_->New<ConstraintWitness>(std::move(impls_constraint_witnesses));
|
||||
}
|
||||
|
||||
auto TypeChecker::MakeConstraintWitnessAccess(Nonnull<const Witness*> witness,
|
||||
@@ -3866,20 +3866,22 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
CARBON_RETURN_IF_ERROR(TypeCheckWhereClause(clause, inner_impl_scope));
|
||||
|
||||
switch (clause->kind()) {
|
||||
case WhereClauseKind::IsWhereClause: {
|
||||
auto& is_clause = cast<IsWhereClause>(*clause);
|
||||
case WhereClauseKind::ImplsWhereClause: {
|
||||
auto& impls_clause = cast<ImplsWhereClause>(*clause);
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
Nonnull<const Value*> type,
|
||||
TypeCheckTypeExp(&is_clause.type(), inner_impl_scope));
|
||||
TypeCheckTypeExp(&impls_clause.type(), inner_impl_scope));
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
Nonnull<const Value*> constraint,
|
||||
InterpExp(&is_clause.constraint(), arena_, trace_stream_));
|
||||
InterpExp(&impls_clause.constraint(), arena_, trace_stream_));
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
Nonnull<const ConstraintType*> constraint_type,
|
||||
ConvertToConstraintType(is_clause.source_loc(),
|
||||
"expression after `is`", constraint));
|
||||
// Transform `where .B is (C where .D is E)` into `where .B is C
|
||||
// and .B.D is E` then add all the resulting constraints.
|
||||
ConvertToConstraintType(impls_clause.source_loc(),
|
||||
"expression after `impls`",
|
||||
constraint));
|
||||
// Transform `where .B impls (C where .D impls E)` into
|
||||
// `where .B impls C and .B.D impls E` then add all the resulting
|
||||
// constraints.
|
||||
CARBON_RETURN_IF_ERROR(
|
||||
builder.AddAndSubstitute(*this, constraint_type, type,
|
||||
builder.GetSelfWitness(), Bindings(),
|
||||
@@ -3915,10 +3917,10 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
<< "` does not name an associated constant";
|
||||
}
|
||||
|
||||
// Find (or add) `.Self is I`, and form a symbolic value naming the
|
||||
// associated constant.
|
||||
// TODO: Reject if the impl constraint didn't already exist.
|
||||
int index = builder.AddImplConstraint(
|
||||
// Find (or add) `.Self impls I`, and form a symbolic value naming
|
||||
// the associated constant.
|
||||
// TODO: Reject if the impls constraint didn't already exist.
|
||||
int index = builder.AddImplsConstraint(
|
||||
{.type = builder.GetSelfType(), .interface = result.interface});
|
||||
const auto* witness =
|
||||
MakeConstraintWitnessAccess(builder.GetSelfWitness(), index);
|
||||
@@ -4023,23 +4025,23 @@ void TypeChecker::CollectImplBindingsInPattern(
|
||||
});
|
||||
}
|
||||
|
||||
void TypeChecker::BringPatternImplsIntoScope(Nonnull<const Pattern*> p,
|
||||
ImplScope& impl_scope) {
|
||||
void TypeChecker::BringPatternImplBindingsIntoScope(Nonnull<const Pattern*> p,
|
||||
ImplScope& impl_scope) {
|
||||
std::vector<Nonnull<const ImplBinding*>> impl_bindings;
|
||||
CollectImplBindingsInPattern(p, impl_bindings);
|
||||
BringImplsIntoScope(impl_bindings, impl_scope);
|
||||
BringImplBindingsIntoScope(impl_bindings, impl_scope);
|
||||
}
|
||||
|
||||
void TypeChecker::BringImplsIntoScope(
|
||||
void TypeChecker::BringImplBindingsIntoScope(
|
||||
llvm::ArrayRef<Nonnull<const ImplBinding*>> impl_bindings,
|
||||
ImplScope& impl_scope) {
|
||||
for (Nonnull<const ImplBinding*> impl_binding : impl_bindings) {
|
||||
BringImplIntoScope(impl_binding, impl_scope);
|
||||
BringImplBindingIntoScope(impl_binding, impl_scope);
|
||||
}
|
||||
}
|
||||
|
||||
void TypeChecker::BringImplIntoScope(Nonnull<const ImplBinding*> impl_binding,
|
||||
ImplScope& impl_scope) {
|
||||
void TypeChecker::BringImplBindingIntoScope(
|
||||
Nonnull<const ImplBinding*> impl_binding, ImplScope& impl_scope) {
|
||||
CARBON_CHECK(impl_binding->type_var()->symbolic_identity().has_value() &&
|
||||
impl_binding->symbolic_identity().has_value());
|
||||
impl_scope.Add(impl_binding->interface(),
|
||||
@@ -4076,15 +4078,16 @@ auto TypeChecker::TypeCheckWhereClause(Nonnull<WhereClause*> clause,
|
||||
const ImplScope& impl_scope)
|
||||
-> ErrorOr<Success> {
|
||||
switch (clause->kind()) {
|
||||
case WhereClauseKind::IsWhereClause: {
|
||||
auto& is_clause = cast<IsWhereClause>(*clause);
|
||||
case WhereClauseKind::ImplsWhereClause: {
|
||||
auto& impls_clause = cast<ImplsWhereClause>(*clause);
|
||||
// TODO: `type` is checked in the caller, because its converted value is
|
||||
// needed. Find a way to move that checking back here.
|
||||
CARBON_RETURN_IF_ERROR(TypeCheckExp(&is_clause.constraint(), impl_scope));
|
||||
if (!isa<TypeType>(is_clause.constraint().static_type())) {
|
||||
return ProgramError(is_clause.constraint().source_loc())
|
||||
<< "expression after `is` does not resolve to a constraint, "
|
||||
<< "found " << is_clause.constraint().static_type();
|
||||
CARBON_RETURN_IF_ERROR(
|
||||
TypeCheckExp(&impls_clause.constraint(), impl_scope));
|
||||
if (!isa<TypeType>(impls_clause.constraint().static_type())) {
|
||||
return ProgramError(impls_clause.constraint().source_loc())
|
||||
<< "expression after `impls` does not resolve to a constraint, "
|
||||
<< "found " << impls_clause.constraint().static_type();
|
||||
}
|
||||
return Success();
|
||||
}
|
||||
@@ -4355,8 +4358,8 @@ auto TypeChecker::TypeCheckGenericBinding(GenericBinding& binding,
|
||||
binding.set_impl_binding(impl_binding);
|
||||
|
||||
// Substitute the VariableType as `.Self` of the constraint to form the
|
||||
// resolved type of the binding. Eg, `T:! X where .Self is Y` resolves
|
||||
// to `T:! <constraint T is X and T is Y>`.
|
||||
// resolved type of the binding. Eg, `T:! X where .Self impls Y` resolves
|
||||
// to `T:! <constraint T impls X and T impls Y>`.
|
||||
ConstraintTypeBuilder builder(arena_, &binding, impl_binding);
|
||||
CARBON_RETURN_IF_ERROR(
|
||||
builder.AddAndSubstitute(*this, constraint, symbolic_value, witness,
|
||||
@@ -4372,7 +4375,7 @@ auto TypeChecker::TypeCheckGenericBinding(GenericBinding& binding,
|
||||
*trace_stream_ << "resolved constraint type is " << *type << "\n";
|
||||
}
|
||||
|
||||
BringImplIntoScope(impl_binding, impl_scope);
|
||||
BringImplBindingIntoScope(impl_binding, impl_scope);
|
||||
}
|
||||
|
||||
binding.set_static_type(type);
|
||||
@@ -4873,10 +4876,10 @@ auto TypeChecker::TypeCheckCallableDeclaration(Nonnull<CallableDeclaration*> f,
|
||||
// If f->return_term().is_auto(), the function body was already
|
||||
// type checked in DeclareFunctionDeclaration.
|
||||
if (f->body().has_value() && !f->return_term().is_auto()) {
|
||||
// Bring the impls into scope.
|
||||
// Bring the impl bindings into scope.
|
||||
ImplScope function_scope(&impl_scope);
|
||||
BringImplsIntoScope(cast<FunctionType>(f->static_type()).impl_bindings(),
|
||||
function_scope);
|
||||
BringImplBindingsIntoScope(
|
||||
cast<FunctionType>(f->static_type()).impl_bindings(), function_scope);
|
||||
if (trace_stream_->is_enabled()) {
|
||||
*trace_stream_ << function_scope;
|
||||
}
|
||||
@@ -5069,7 +5072,7 @@ auto TypeChecker::TypeCheckClassDeclaration(
|
||||
}
|
||||
ImplScope class_scope(&impl_scope);
|
||||
if (class_decl->type_params().has_value()) {
|
||||
BringPatternImplsIntoScope(*class_decl->type_params(), class_scope);
|
||||
BringPatternImplBindingsIntoScope(*class_decl->type_params(), class_scope);
|
||||
}
|
||||
if (trace_stream_->is_enabled()) {
|
||||
*trace_stream_ << class_scope;
|
||||
@@ -5157,7 +5160,7 @@ auto TypeChecker::TypeCheckMixinDeclaration(
|
||||
}
|
||||
ImplScope mixin_scope(&impl_scope);
|
||||
if (mixin_decl->params().has_value()) {
|
||||
BringPatternImplsIntoScope(*mixin_decl->params(), mixin_scope);
|
||||
BringPatternImplBindingsIntoScope(*mixin_decl->params(), mixin_scope);
|
||||
}
|
||||
if (trace_stream_->is_enabled()) {
|
||||
*trace_stream_ << mixin_scope;
|
||||
@@ -5282,12 +5285,12 @@ auto TypeChecker::DeclareConstraintTypeDeclaration(
|
||||
// this interface.
|
||||
std::optional<Nonnull<const Witness*>> iface_impl_witness;
|
||||
if (is_interface) {
|
||||
// The impl constraint says only that the direct members of the interface
|
||||
// The impls constraint says only that the direct members of the interface
|
||||
// are available. For any indirect constraints, we need to add separate
|
||||
// entries to the constraint type. This ensures that all indirect
|
||||
// constraints are lifted to the top level so they can be accessed directly
|
||||
// and resolved independently if necessary.
|
||||
int index = builder.AddImplConstraint(
|
||||
int index = builder.AddImplsConstraint(
|
||||
{.type = builder.GetSelfType(),
|
||||
.interface = cast<InterfaceType>(constraint_type)});
|
||||
iface_impl_witness =
|
||||
@@ -5303,7 +5306,8 @@ auto TypeChecker::DeclareConstraintTypeDeclaration(
|
||||
// to update state that's not available from there.
|
||||
switch (m->kind()) {
|
||||
case DeclarationKind::InterfaceExtendsDeclaration: {
|
||||
// For an `extends C;` declaration, add `Self is C` to our constraint.
|
||||
// For an `extends C;` declaration, add `Self impls C` to our
|
||||
// constraint.
|
||||
auto* extends = cast<InterfaceExtendsDeclaration>(m);
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
Nonnull<const Value*> base,
|
||||
@@ -5320,7 +5324,7 @@ auto TypeChecker::DeclareConstraintTypeDeclaration(
|
||||
}
|
||||
|
||||
case DeclarationKind::InterfaceImplDeclaration: {
|
||||
// For an `impl X as Y;` declaration, add `X is Y` to our constraint.
|
||||
// For an `impl X as Y;` declaration, add `X impls Y` to our constraint.
|
||||
auto* impl = cast<InterfaceImplDeclaration>(m);
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
Nonnull<const Value*> impl_type,
|
||||
@@ -5364,8 +5368,8 @@ auto TypeChecker::DeclareConstraintTypeDeclaration(
|
||||
|
||||
// The type specified for the associated constant becomes a
|
||||
// constraint for the constraint type: `let X:! Interface` adds a
|
||||
// `Self.X is Interface` constraint that `impl`s must satisfy and users
|
||||
// of the constraint type can rely on.
|
||||
// `Self.X impls Interface` constraint that `impl` declarations must
|
||||
// satisfy and users of the constraint type can rely on.
|
||||
if (const auto* constraint_type =
|
||||
dyn_cast<ConstraintType>(constraint)) {
|
||||
CARBON_RETURN_IF_ERROR(
|
||||
@@ -5393,7 +5397,7 @@ auto TypeChecker::DeclareConstraintTypeDeclaration(
|
||||
}
|
||||
}
|
||||
|
||||
// Add any new impl constraints to the scope.
|
||||
// Add any new impls constraints to the scope.
|
||||
builder.BringConstraintsIntoScope(*this, &constraint_scope,
|
||||
&constraint_tracker);
|
||||
}
|
||||
@@ -5418,7 +5422,8 @@ auto TypeChecker::TypeCheckConstraintTypeDeclaration(
|
||||
}
|
||||
ImplScope constraint_scope(&impl_scope);
|
||||
if (constraint_decl->params().has_value()) {
|
||||
BringPatternImplsIntoScope(*constraint_decl->params(), constraint_scope);
|
||||
BringPatternImplBindingsIntoScope(*constraint_decl->params(),
|
||||
constraint_scope);
|
||||
}
|
||||
if (trace_stream_->is_enabled()) {
|
||||
*trace_stream_ << constraint_scope;
|
||||
@@ -5506,7 +5511,7 @@ auto TypeChecker::CheckAndAddImplBindings(
|
||||
const ScopeInfo& scope_info) -> ErrorOr<Success> {
|
||||
// Each interface that is a lookup context is required to be implemented by
|
||||
// the impl members. Other constraints are required to be satisfied by
|
||||
// either those impls or impls available elsewhere.
|
||||
// either those implementations or implementations available elsewhere.
|
||||
Nonnull<const ConstraintType*> constraint = impl_decl->constraint_type();
|
||||
for (auto lookup : constraint->lookup_contexts()) {
|
||||
if (const auto* iface_type = dyn_cast<InterfaceType>(lookup.context)) {
|
||||
@@ -5648,15 +5653,15 @@ auto TypeChecker::DeclareImplDeclaration(Nonnull<ImplDeclaration*> impl_decl,
|
||||
builder.GetSelfWitness(), Bindings(),
|
||||
/*add_lookup_contexts=*/true));
|
||||
if (trace_stream_->is_enabled()) {
|
||||
*trace_stream_ << "resolving impl constraint type for " << *impl_decl
|
||||
*trace_stream_ << "resolving impls constraint type for " << *impl_decl
|
||||
<< " from " << *implemented_constraint << "\n";
|
||||
}
|
||||
CARBON_RETURN_IF_ERROR(builder.Resolve(
|
||||
*this, impl_decl->interface().source_loc(), impl_scope));
|
||||
constraint_type = std::move(builder).Build();
|
||||
if (trace_stream_->is_enabled()) {
|
||||
*trace_stream_ << "resolving impl constraint type as " << *constraint_type
|
||||
<< "\n";
|
||||
*trace_stream_ << "resolving impls constraint type as "
|
||||
<< *constraint_type << "\n";
|
||||
}
|
||||
impl_decl->set_constraint_type(constraint_type);
|
||||
}
|
||||
@@ -5764,9 +5769,9 @@ auto TypeChecker::TypeCheckImplDeclaration(Nonnull<ImplDeclaration*> impl_decl,
|
||||
Nonnull<const Value*> self = *impl_decl->self()->constant_value();
|
||||
Nonnull<const ConstraintType*> constraint = impl_decl->constraint_type();
|
||||
|
||||
// Bring the impls from the parameters into scope.
|
||||
// Bring the impl bindings from the parameters into scope.
|
||||
ImplScope impl_scope(&enclosing_scope);
|
||||
BringImplsIntoScope(impl_decl->impl_bindings(), impl_scope);
|
||||
BringImplBindingsIntoScope(impl_decl->impl_bindings(), impl_scope);
|
||||
for (Nonnull<Declaration*> m : impl_decl->members()) {
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
ConstraintLookupResult result,
|
||||
@@ -5966,7 +5971,7 @@ auto TypeChecker::TypeCheckDeclaration(
|
||||
}
|
||||
case DeclarationKind::MatchFirstDeclaration: {
|
||||
auto* match_first = cast<MatchFirstDeclaration>(d);
|
||||
for (auto* impl : match_first->impls()) {
|
||||
for (auto* impl : match_first->impl_declarations()) {
|
||||
impl->set_match_first(match_first);
|
||||
CARBON_RETURN_IF_ERROR(TypeCheckImplDeclaration(impl, impl_scope));
|
||||
}
|
||||
@@ -6057,7 +6062,7 @@ auto TypeChecker::DeclareDeclaration(Nonnull<Declaration*> d,
|
||||
break;
|
||||
}
|
||||
case DeclarationKind::MatchFirstDeclaration: {
|
||||
for (auto* impl : cast<MatchFirstDeclaration>(d)->impls()) {
|
||||
for (auto* impl : cast<MatchFirstDeclaration>(d)->impl_declarations()) {
|
||||
CARBON_RETURN_IF_ERROR(DeclareImplDeclaration(
|
||||
impl, scope_info, /*is_template_instantiation=*/false));
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ class TypeChecker {
|
||||
// `type`, then return the witness for this `impl`. Otherwise return
|
||||
// std::nullopt.
|
||||
auto MatchImpl(const InterfaceType& iface, Nonnull<const Value*> type,
|
||||
const ImplScope::Impl& impl, const ImplScope& impl_scope,
|
||||
const ImplScope::ImplFact& impl, const ImplScope& impl_scope,
|
||||
SourceLocation source_loc) const
|
||||
-> ErrorOr<std::optional<Nonnull<const Witness*>>>;
|
||||
|
||||
@@ -105,7 +105,7 @@ class TypeChecker {
|
||||
// Given the witnesses for the components of a constraint, form a witness for
|
||||
// the constraint.
|
||||
auto MakeConstraintWitness(
|
||||
std::vector<Nonnull<const Witness*>> impl_constraint_witnesses) const
|
||||
std::vector<Nonnull<const Witness*>> impls_constraint_witnesses) const
|
||||
-> Nonnull<const Witness*>;
|
||||
|
||||
// Given the witnesses for the components of a constraint, form a witness for
|
||||
@@ -143,11 +143,11 @@ class TypeChecker {
|
||||
.bindings = std::move(class_bindings)};
|
||||
}
|
||||
|
||||
// The innermost enclosing impl scope, within which impls should be looked
|
||||
// up.
|
||||
// The innermost enclosing impl scope, within which impl declarations should
|
||||
// be looked up.
|
||||
Nonnull<ImplScope*> innermost_scope;
|
||||
// The innermost enclosing non-class impl scope, where impl declarations
|
||||
// should introduce new impls.
|
||||
// should introduce new implementations.
|
||||
Nonnull<ImplScope*> innermost_non_class_scope;
|
||||
// The enclosing generic bindings, if any.
|
||||
std::vector<Nonnull<const GenericBinding*>> bindings;
|
||||
@@ -192,7 +192,7 @@ class TypeChecker {
|
||||
// surrounding context gives us that information. Otherwise, it is nullopt.
|
||||
// Implicit conversions from `expected` to the pattern's type are permitted.
|
||||
//
|
||||
// `impl_scope` is extended with all impls implied by the pattern.
|
||||
// `impl_scope` is extended with all implementations implied by the pattern.
|
||||
auto TypeCheckPattern(Nonnull<Pattern*> p,
|
||||
std::optional<Nonnull<const Value*>> expected,
|
||||
ImplScope& impl_scope,
|
||||
@@ -214,7 +214,7 @@ class TypeChecker {
|
||||
-> ErrorOr<Success>;
|
||||
|
||||
// Perform deduction for the deduced bindings in a function call, and set its
|
||||
// lists of generic bindings and impls.
|
||||
// lists of generic bindings and implementations.
|
||||
//
|
||||
// - `params` is the list of parameters.
|
||||
// - `generic_params` indicates which parameters are generic parameters,
|
||||
@@ -302,20 +302,20 @@ class TypeChecker {
|
||||
Nonnull<const Pattern*> p,
|
||||
std::vector<Nonnull<const ImplBinding*>>& impl_bindings);
|
||||
|
||||
// Add the impls from the pattern into the given `impl_scope`.
|
||||
void BringPatternImplsIntoScope(Nonnull<const Pattern*> p,
|
||||
ImplScope& impl_scope);
|
||||
// Add the impl bindings from the pattern into the given `impl_scope`.
|
||||
void BringPatternImplBindingsIntoScope(Nonnull<const Pattern*> p,
|
||||
ImplScope& impl_scope);
|
||||
|
||||
// Create a witness for the given `impl` binding.
|
||||
auto CreateImplBindingWitness(Nonnull<const ImplBinding*> impl_binding)
|
||||
-> Nonnull<const Witness*>;
|
||||
|
||||
// Add the given ImplBinding to the given `impl_scope`.
|
||||
void BringImplIntoScope(Nonnull<const ImplBinding*> impl_binding,
|
||||
ImplScope& impl_scope);
|
||||
void BringImplBindingIntoScope(Nonnull<const ImplBinding*> impl_binding,
|
||||
ImplScope& impl_scope);
|
||||
|
||||
// Add all of the `impl_bindings` into the `scope`.
|
||||
void BringImplsIntoScope(
|
||||
void BringImplBindingsIntoScope(
|
||||
llvm::ArrayRef<Nonnull<const ImplBinding*>> impl_bindings,
|
||||
ImplScope& scope);
|
||||
|
||||
@@ -436,8 +436,8 @@ class TypeChecker {
|
||||
const ImplScope& impl_scope) const -> ErrorOr<Success>;
|
||||
|
||||
// Rebuild a value in the current type-checking context. Applies any rewrites
|
||||
// that are in scope and attempts to resolve associated constants using impls
|
||||
// that have been declared since the value was formed.
|
||||
// that are in scope and attempts to resolve associated constants using
|
||||
// implementations that have been declared since the value was formed.
|
||||
auto RebuildValue(Nonnull<const Value*> value) const
|
||||
-> ErrorOr<Nonnull<const Value*>>;
|
||||
|
||||
@@ -544,7 +544,7 @@ class TypeChecker {
|
||||
// rewrites that are not yet visible in any type.
|
||||
std::vector<ConstraintTypeBuilder*> partial_constraint_types_;
|
||||
|
||||
// A set of impls we're currently matching.
|
||||
// A set of implementations we're currently matching.
|
||||
// TODO: This is `mutable` because `MatchImpl` is `const`. We need to remove
|
||||
// the `const`s from everywhere that transitively does `impl` matching to get
|
||||
// rid of this `mutable`.
|
||||
|
||||
@@ -86,7 +86,7 @@ struct TypeStructureBuilder {
|
||||
|
||||
// Constraint types can contain mentions of VariableTypes, but they aren't
|
||||
// deducible so it's not important to look for them.
|
||||
void Visit(const ImplConstraint&) {}
|
||||
void Visit(const ImplsConstraint&) {}
|
||||
void Visit(const IntrinsicConstraint&) {}
|
||||
void Visit(const EqualityConstraint&) {}
|
||||
void Visit(const RewriteConstraint&) {}
|
||||
|
||||
@@ -76,10 +76,10 @@ GREATER_GREATER ">>"
|
||||
GREATER_GREATER_EQUAL ">>="
|
||||
IF "if"
|
||||
IMPL "impl"
|
||||
IMPLS "impls"
|
||||
IMPORT "import"
|
||||
IN "in"
|
||||
INTERFACE "interface"
|
||||
IS "is"
|
||||
LEFT_CURLY_BRACE "{"
|
||||
LEFT_PARENTHESIS "("
|
||||
LEFT_SQUARE_BRACKET "["
|
||||
@@ -198,11 +198,11 @@ operand_start [(A-Za-z0-9_\"]
|
||||
{GREATER_GREATER} { return CARBON_SIMPLE_TOKEN(GREATER_GREATER); }
|
||||
{GREATER} { return CARBON_SIMPLE_TOKEN(GREATER); }
|
||||
{IF} { return CARBON_SIMPLE_TOKEN(IF); }
|
||||
{IMPLS} { return CARBON_SIMPLE_TOKEN(IMPLS); }
|
||||
{IMPL} { return CARBON_SIMPLE_TOKEN(IMPL); }
|
||||
{IMPORT} { return CARBON_SIMPLE_TOKEN(IMPORT); }
|
||||
{INTERFACE} { return CARBON_SIMPLE_TOKEN(INTERFACE); }
|
||||
{IN} { return CARBON_SIMPLE_TOKEN(IN); }
|
||||
{IS} { return CARBON_SIMPLE_TOKEN(IS); }
|
||||
{LEFT_CURLY_BRACE} { return CARBON_SIMPLE_TOKEN(LEFT_CURLY_BRACE); }
|
||||
{LEFT_PARENTHESIS} { return CARBON_SIMPLE_TOKEN(LEFT_PARENTHESIS); }
|
||||
{LEFT_SQUARE_BRACKET} { return CARBON_SIMPLE_TOKEN(LEFT_SQUARE_BRACKET); }
|
||||
|
||||
@@ -252,10 +252,10 @@
|
||||
GREATER_GREATER_EQUAL
|
||||
IF
|
||||
IMPL
|
||||
IMPLS
|
||||
IMPORT
|
||||
IN
|
||||
INTERFACE
|
||||
IS
|
||||
LEFT_CURLY_BRACE
|
||||
LEFT_PARENTHESIS
|
||||
LEFT_SQUARE_BRACKET
|
||||
@@ -721,8 +721,8 @@ or_expression:
|
||||
}
|
||||
;
|
||||
where_clause:
|
||||
comparison_operand IS comparison_operand
|
||||
{ $$ = arena->New<IsWhereClause>(context.source_loc(), $1, $3); }
|
||||
comparison_operand IMPLS comparison_operand
|
||||
{ $$ = arena->New<ImplsWhereClause>(context.source_loc(), $1, $3); }
|
||||
| comparison_operand EQUAL_EQUAL comparison_operand
|
||||
{ $$ = arena->New<EqualsWhereClause>(context.source_loc(), $1, $3); }
|
||||
// TODO: .(expression) = expression
|
||||
|
||||
@@ -16,9 +16,9 @@ interface Y(T:! type) {
|
||||
}
|
||||
|
||||
interface Z {
|
||||
// The `i32 is X(.Self)` constraint is indirectly required by
|
||||
// The `i32 impls X(.Self)` constraint is indirectly required by
|
||||
// specifying that `.M = i32`.
|
||||
let N:! Y(.Self) where i32 is X(.Self) and .M = i32;
|
||||
let N:! Y(.Self) where i32 impls X(.Self) and .M = i32;
|
||||
}
|
||||
|
||||
impl i32 as X(i32) {}
|
||||
|
||||
@@ -25,11 +25,11 @@ interface HasParams(A:! type, B:! type, C:! type, D:! type) {
|
||||
// Here we discover that there is a rewrite for `HasParams(...).V` only after
|
||||
// substitution converts each one to `HasParam(X, X, X, X).V`.
|
||||
fn F[X:! (HasTypes & HasParams(.Self, .Self, .Self, .Self)) where
|
||||
.Self is HasParams(.A, .A, .A, .A) and
|
||||
.Self is HasParams(.B, .B, .B, .B) and
|
||||
.Self is HasParams(.C, .C, .C, .C) and
|
||||
.Self is HasParams(.D, .D, .D, .D) and
|
||||
.Self is HasParams(.E, .E, .E, .E) and
|
||||
.Self impls HasParams(.A, .A, .A, .A) and
|
||||
.Self impls HasParams(.B, .B, .B, .B) and
|
||||
.Self impls HasParams(.C, .C, .C, .C) and
|
||||
.Self impls HasParams(.D, .D, .D, .D) and
|
||||
.Self impls HasParams(.E, .E, .E, .E) and
|
||||
.F = .Self.(HasParams(.E, .E, .E, .E).V).A and
|
||||
.E = .Self.(HasParams(.D, .D, .D, .D).V).A and
|
||||
.D = .Self.(HasParams(.C, .C, .C, .C).V).A and
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ impl i32 as A { fn F() -> i32 { return 1; } }
|
||||
impl i32 as B { fn F() -> i32 { return 2; } }
|
||||
|
||||
fn GetA[T:! A](x: T) -> i32 { return x.F(); }
|
||||
fn GetAB[T:! B where .Self is A](x: T) -> i32 {
|
||||
fn GetAB[T:! B where .Self impls A](x: T) -> i32 {
|
||||
// Note that there's no ambiguity in the use of the name F here.
|
||||
// `x.F` is `x.(B.F)` because the constraint only treats `B`, not
|
||||
// `A`, as a lookup context.
|
||||
|
||||
@@ -13,7 +13,7 @@ impl i32 as I {}
|
||||
|
||||
fn F(A:! i32, B:! i32, C:! i32, D:! i32, E:! i32,
|
||||
T:! I where A == B and C == D and C == E and B == D) {
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/fail_combine_equality.carbon:[[@LINE+1]]: member access, F not in interface I where T is interface I and A == B and C == D and C == E and B == D
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/fail_combine_equality.carbon:[[@LINE+1]]: member access, F not in interface I where T impls interface I and A == B and C == D and C == E and B == D
|
||||
T.F();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ package ExplorerTest api;
|
||||
interface A { fn F() -> i32; }
|
||||
interface B { fn G() -> i32; }
|
||||
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/fail_missing_member.carbon:[[@LINE+1]]: member access, H not in interface A & interface B where T is interface A and T is interface B
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/fail_missing_member.carbon:[[@LINE+1]]: member access, H not in interface A & interface B where T impls interface A and T impls interface B
|
||||
fn Get[T:! A & B](n: T) -> i32 { return n.H(); }
|
||||
|
||||
impl i32 as A {
|
||||
|
||||
+2
-2
@@ -10,7 +10,7 @@ package ExplorerTest api;
|
||||
|
||||
interface A {}
|
||||
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/fail_where_is_non_constraint.carbon:[[@LINE+1]]: expected a constraint in expression after `is`, found i32
|
||||
alias B = A where i32 is i32;
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/fail_where_impls_non_constraint.carbon:[[@LINE+1]]: expected a constraint in expression after `impls`, found i32
|
||||
alias B = A where i32 impls i32;
|
||||
|
||||
fn Main() -> i32 { return 0; }
|
||||
+2
-2
@@ -10,7 +10,7 @@ package ExplorerTest api;
|
||||
|
||||
interface A {}
|
||||
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/fail_where_is_non_type.carbon:[[@LINE+1]]: expression after `is` does not resolve to a constraint, found i32
|
||||
alias B = A where i32 is 5;
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/fail_where_impls_non_type.carbon:[[@LINE+1]]: expression after `impls` does not resolve to a constraint, found i32
|
||||
alias B = A where i32 impls 5;
|
||||
|
||||
fn Main() -> i32 { return 0; }
|
||||
+2
-2
@@ -10,7 +10,7 @@ package ExplorerTest api;
|
||||
|
||||
interface A {}
|
||||
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/fail_where_non_type_is.carbon:[[@LINE+1]]: type error in type expression: 'i32' is not implicitly convertible to 'type'
|
||||
alias B = A where 4 is A;
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/fail_where_non_type_impls.carbon:[[@LINE+1]]: type error in type expression: 'i32' is not implicitly convertible to 'type'
|
||||
alias B = A where 4 impls A;
|
||||
|
||||
fn Main() -> i32 { return 0; }
|
||||
+1
-1
@@ -12,7 +12,7 @@ package ExplorerTest api;
|
||||
interface A { fn Get() -> Self; }
|
||||
impl i32 as A { fn Get() -> Self { return 1; } }
|
||||
|
||||
alias AlsoA = A where i32 is A and 4 == 4;
|
||||
alias AlsoA = A where i32 impls A and 4 == 4;
|
||||
|
||||
fn F[T:! AlsoA](x: T) -> T { return T.Get(); }
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ interface B { fn F() -> i32; }
|
||||
impl i32 as A { fn F() -> i32 { return 1; } }
|
||||
impl i32 as B { fn F() -> i32 { return 2; } }
|
||||
|
||||
fn GetAB(T:! B where .Self is A) -> i32 {
|
||||
fn GetAB(T:! B where .Self impls A) -> i32 {
|
||||
return 100 * T.(A.F)() + 10 * T.(B.F)() + T.F();
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -18,7 +18,7 @@ interface Extension {
|
||||
extends Base;
|
||||
}
|
||||
|
||||
fn F[T:! type where .Self is Extension](x: T) {
|
||||
fn F[T:! type where .Self impls Extension](x: T) {
|
||||
x.(Extension.F)();
|
||||
}
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ interface SwizzleWith(T:! type) {
|
||||
|
||||
// TODO: There should be some way to write this that includes
|
||||
// `SwizzleWith(.Self)` in the list of lookup contexts.
|
||||
alias Swizzle = type where .Self is SwizzleWith(.Self);
|
||||
alias Swizzle = type where .Self impls SwizzleWith(.Self);
|
||||
|
||||
impl i32 as SwizzleWith(i32) {
|
||||
fn Op[self: Self](x: Self) -> Self { return self * 10 + x; }
|
||||
|
||||
+2
-2
@@ -11,8 +11,8 @@ package ExplorerTest api;
|
||||
interface A {}
|
||||
interface B {}
|
||||
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/impl/fail_unmet_impl_constraint.carbon:[[@LINE+1]]: could not find implementation of interface B for i32
|
||||
external impl i32 as A where i32 is B {}
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/impl/fail_unmet_impls_constraint.carbon:[[@LINE+1]]: could not find implementation of interface B for i32
|
||||
external impl i32 as A where i32 impls B {}
|
||||
|
||||
fn Main() -> i32 {
|
||||
return 0;
|
||||
Vendored
+1
-1
@@ -24,7 +24,7 @@ external impl i32 as A {
|
||||
fn F() -> i32 { return 1; }
|
||||
}
|
||||
|
||||
external impl i32 as B & C(i32) where .Self is A {
|
||||
external impl i32 as B & C(i32) where .Self impls A {
|
||||
fn F() -> i32 { return 2; }
|
||||
fn G() -> i32 { return 3; }
|
||||
fn H() -> i32 { return 4; }
|
||||
+1
-1
@@ -10,7 +10,7 @@ package ExplorerTest api;
|
||||
|
||||
interface Foo {}
|
||||
|
||||
impl forall [T:! type where .Self* is Foo] T as Foo {}
|
||||
impl forall [T:! type where .Self* impls Foo] T as Foo {}
|
||||
|
||||
fn F[T:! Foo](x: T) {}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ package ExplorerTest api;
|
||||
interface Foo {}
|
||||
|
||||
impl forall [T:! type where .Self == i32*] T as Foo {}
|
||||
impl forall [T:! type where .Self* is Foo] T as Foo {}
|
||||
impl forall [T:! type where .Self* impls Foo] T as Foo {}
|
||||
|
||||
fn F[T:! Foo](x: T) {}
|
||||
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ package ExplorerTest api;
|
||||
|
||||
interface Foo {}
|
||||
|
||||
impl forall [T:! type where {.a: .Self} is Foo] T as Foo {}
|
||||
impl forall [T:! type where {.a: .Self} impls Foo] T as Foo {}
|
||||
|
||||
fn F[T:! Foo](x: T) {}
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ interface A {}
|
||||
interface B {}
|
||||
interface C {}
|
||||
|
||||
impl forall [T:! type where .Self* is A] T as B {}
|
||||
impl forall [T:! type where .Self* is B] T as C {}
|
||||
impl forall [T:! type where .Self* is C] T as A {}
|
||||
impl forall [T:! type where .Self* impls A] T as B {}
|
||||
impl forall [T:! type where .Self* impls B] T as C {}
|
||||
impl forall [T:! type where .Self* impls C] T as A {}
|
||||
|
||||
fn F[T:! A](x: T) {}
|
||||
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ package ExplorerTest api;
|
||||
|
||||
interface Foo {}
|
||||
|
||||
impl forall [T:! type where (.Self,) is Foo] T as Foo {}
|
||||
impl forall [T:! type where (.Self,) impls Foo] T as Foo {}
|
||||
|
||||
fn F[T:! Foo](x: T) {}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ package ExplorerTest api;
|
||||
interface Foo {}
|
||||
|
||||
impl i32* as Foo {}
|
||||
impl forall [T:! type where .Self* is Foo] T as Foo {}
|
||||
impl forall [T:! type where .Self* impls Foo] T as Foo {}
|
||||
|
||||
fn F[T:! Foo](x: T) {}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ interface Foo {}
|
||||
|
||||
__match_first {
|
||||
impl forall [T:! type where .Self == i32*] T as Foo {}
|
||||
impl forall [T:! type where .Self* is Foo] T as Foo {}
|
||||
impl forall [T:! type where .Self* impls Foo] T as Foo {}
|
||||
}
|
||||
|
||||
fn F[T:! Foo](x: T) {}
|
||||
|
||||
@@ -13,7 +13,7 @@ interface Vector {
|
||||
}
|
||||
|
||||
fn ScaleGeneric[T:! Vector](a: T, s: i32) -> T {
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/interface/fail_interface_missing_member.carbon:[[@LINE+1]]: member access, Scale not in interface Vector where T is interface Vector
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/interface/fail_interface_missing_member.carbon:[[@LINE+1]]: member access, Scale not in interface Vector where T impls interface Vector
|
||||
return a.Scale(s);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
package ExplorerTest api;
|
||||
|
||||
// The bodies of member functions are processed after all immediately enclosing
|
||||
// classes, impls, and interfaces.
|
||||
// classes, impl declarations, and interfaces.
|
||||
class A {
|
||||
fn F[self: Self]() -> i32 {
|
||||
return G() + self.H();
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
package ExplorerTest api;
|
||||
|
||||
// The bodies of member functions are processed after all immediately enclosing
|
||||
// classes, impls, and interfaces.
|
||||
// classes, impl declarations, and interfaces.
|
||||
class A {
|
||||
fn F() -> type {
|
||||
return i32;
|
||||
|
||||
@@ -19,7 +19,7 @@ constraint ImplAsHasFoo {
|
||||
fn CallFoo[T:! ImplAsHasFoo](x: T) {
|
||||
// OK, T is HasFoo.
|
||||
x.(HasFoo.Foo)();
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/named_constraint/fail_impl_as_member_access.carbon:[[@LINE+1]]: member access, Foo not in constraint ImplAsHasFoo where T is interface HasFoo
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/named_constraint/fail_impl_as_member_access.carbon:[[@LINE+1]]: member access, Foo not in constraint ImplAsHasFoo where T impls interface HasFoo
|
||||
x.Foo();
|
||||
}
|
||||
|
||||
|
||||
@@ -136,6 +136,7 @@ CARBON_KEYWORD_TOKEN(For, "for")
|
||||
CARBON_KEYWORD_TOKEN(Friend, "friend")
|
||||
CARBON_KEYWORD_TOKEN(If, "if")
|
||||
CARBON_KEYWORD_TOKEN(Impl, "impl")
|
||||
CARBON_KEYWORD_TOKEN(Impls, "impls")
|
||||
CARBON_KEYWORD_TOKEN(Import, "import")
|
||||
CARBON_KEYWORD_TOKEN(In, "in")
|
||||
CARBON_KEYWORD_TOKEN(Interface, "interface")
|
||||
|
||||
Reference in New Issue
Block a user