Explorer and toolchain changes to implement #2483 (#2707)

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:
josh11b
2023-03-28 12:28:52 -07:00
committed by GitHub
co-authored by Geoff Romer
parent 7fc203c536
commit 46503c0a9d
64 changed files with 335 additions and 302 deletions
+3 -3
View File
@@ -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 {
+5 -5
View File
@@ -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";
}
+1 -1
View File
@@ -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;
+2 -1
View File
@@ -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";
+13 -8
View File
@@ -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 {
+3 -3
View File
@@ -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
View File
@@ -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_; }
+1 -1
View File
@@ -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:
+7 -7
View File
@@ -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
View File
@@ -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:
+13 -13
View File
@@ -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;
+8 -8
View File
@@ -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;
}
@@ -32,7 +32,7 @@ compilation_unit {
}
}
clauses {
is {
impls {
type {
int_type_literal {
}
@@ -76,3 +76,4 @@ compilation_unit {
}
}
}
@@ -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 {
@@ -82,7 +82,7 @@ compilation_unit {
}
}
clauses {
is {
impls {
type {
int_type_literal {
}
@@ -239,3 +239,4 @@ compilation_unit {
}
}
}
@@ -66,7 +66,7 @@ compilation_unit {
}
}
clauses {
is {
impls {
type {
designator {
name: "Self"
@@ -393,3 +393,4 @@ compilation_unit {
}
}
}
@@ -148,7 +148,7 @@ compilation_unit {
}
}
clauses {
is {
impls {
type {
designator {
name: "Self"
@@ -323,3 +323,4 @@ compilation_unit {
}
}
}
@@ -23,7 +23,7 @@ compilation_unit {
}
}
clauses {
is {
impls {
type {
int_literal {
value: 4
@@ -68,3 +68,4 @@ compilation_unit {
}
}
}
@@ -75,7 +75,7 @@ compilation_unit {
}
}
clauses {
is {
impls {
type {
int_type_literal {
}
@@ -300,3 +300,4 @@ compilation_unit {
}
}
}
@@ -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 {
@@ -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 {
}
}
}
@@ -23,7 +23,7 @@ compilation_unit {
}
}
clauses {
is {
impls {
type {
int_type_literal {
}
@@ -66,3 +66,4 @@ compilation_unit {
}
}
}
@@ -23,7 +23,7 @@ compilation_unit {
}
}
clauses {
is {
impls {
type {
int_type_literal {
}
@@ -67,3 +67,4 @@ compilation_unit {
}
}
}
@@ -208,7 +208,7 @@ compilation_unit {
}
}
clauses {
is {
impls {
type {
designator {
name: "Self"
@@ -370,3 +370,4 @@ compilation_unit {
}
}
}
@@ -52,7 +52,7 @@ compilation_unit {
}
}
clauses {
is {
impls {
type {
designator {
name: "Self"
@@ -245,3 +245,4 @@ compilation_unit {
}
}
}
@@ -167,7 +167,7 @@ compilation_unit {
}
}
clauses {
is {
impls {
type {
designator {
name: "Self"
@@ -476,3 +476,4 @@ compilation_unit {
}
}
}
+29 -27
View File
@@ -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;
+11 -11
View File
@@ -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_;
};
+11 -10
View File
@@ -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>{});
+1 -1
View File
@@ -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) {
+2 -2
View File
@@ -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;
+7 -5
View File
@@ -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;
+97 -92
View File
@@ -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));
}
+16 -16
View File
@@ -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`.
+1 -1
View File
@@ -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&) {}
+2 -2
View File
@@ -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); }
+3 -3
View File
@@ -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
View File
@@ -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.
+1 -1
View File
@@ -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
View File
@@ -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 {
@@ -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; }
@@ -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; }
@@ -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
View File
@@ -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();
}
@@ -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
View File
@@ -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; }
@@ -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;
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
+1 -1
View File
@@ -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();
}
+1
View File
@@ -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")