Basic support for .Self within :! bindings and where expressions. (#1311)

`.Self` is modeled as a new kind of expression, `DotSelfExpression`. Name resolution associates each occurrence of a `DotSelfExpression` with a generic binding, much like for an `IdentifierExpression`.

Both `:!` bindings and `where` expressions bring `.Self` into scope. The tentative intent is that if there are multiple `.Self`s in scope and they refer to different bindings, the result of using a `.Self` expression is an ambiguity error, but that is not implemented in this patch. Instead, like for `IdentifierExpression`s, we find the innermost enclosing definition of `.Self`.

`.Foo` expressions are rewritten to `.Self.Foo`, but this isn't enough to make them do anything useful, because associated constants aren't supported in general yet.
This commit is contained in:
Richard Smith
2022-06-14 21:49:01 -07:00
committed by GitHub
parent b83f5c3fc7
commit 2fef76e58c
26 changed files with 418 additions and 67 deletions
+5
View File
@@ -79,6 +79,10 @@ message IdentifierExpression {
optional string name = 1;
}
message DesignatorExpression {
optional string name = 1;
}
message IntrinsicExpression {
enum Intrinsic {
UnknownIntrinsic = 0;
@@ -170,6 +174,7 @@ message Expression {
ArrayTypeLiteral array_type_literal = 21;
CompoundMemberAccessExpression compound_member_access = 22;
WhereExpression where = 23;
DesignatorExpression designator = 24;
}
}
+7
View File
@@ -275,6 +275,13 @@ static auto ExpressionToCarbon(const Fuzzing::Expression& expression,
break;
}
case Fuzzing::Expression::kDesignator: {
const auto& designator = expression.designator();
out << ".";
IdentifierToCarbon(designator.name(), out);
break;
}
case Fuzzing::Expression::kIntrinsic: {
const auto& intrinsic = expression.intrinsic();
switch (intrinsic.intrinsic()) {
+4 -24
View File
@@ -64,7 +64,6 @@ cc_test(
":ast_test_matchers",
":declaration",
":expression",
":pattern",
":statement",
"//common:gtest_main",
"//explorer/common:arena",
@@ -79,7 +78,7 @@ cc_library(
],
deps = [
":ast_node",
":pattern",
":expression",
":value_category",
"//common:check",
"//common:ostream",
@@ -98,7 +97,7 @@ cc_library(
deps = [
":ast_node",
":impl_binding",
":pattern",
":expression",
":return_term",
":statement",
":static_scope",
@@ -125,8 +124,8 @@ cc_library(
cc_library(
name = "expression",
srcs = ["expression.cpp"],
hdrs = ["expression.h"],
srcs = ["expression.cpp", "pattern.cpp"],
hdrs = ["expression.h", "pattern.h"],
deps = [
":ast_node",
":paren_contents",
@@ -168,30 +167,12 @@ cc_library(
],
)
cc_library(
name = "pattern",
srcs = ["pattern.cpp"],
hdrs = ["pattern.h"],
deps = [
":ast_node",
":expression",
":static_scope",
":value_category",
"//common:ostream",
"//explorer/common:arena",
"//explorer/common:error_builders",
"//explorer/common:source_location",
"@llvm-project//llvm:Support",
],
)
cc_test(
name = "pattern_test",
srcs = ["pattern_test.cpp"],
deps = [
":expression",
":paren_contents",
":pattern",
"//common:gtest_main",
"//explorer/common:arena",
"@com_google_googletest//:gtest",
@@ -222,7 +203,6 @@ cc_library(
deps = [
":ast_node",
":expression",
":pattern",
":return_term",
":static_scope",
":value_category",
+1
View File
@@ -57,6 +57,7 @@ abstract class Expression : AstNode;
class TypeTypeLiteral : Expression;
class ValueLiteral : Expression;
class IdentifierExpression : Expression;
class DotSelfExpression : Expression;
class IntrinsicExpression : Expression;
class IfExpression : Expression;
class WhereExpression : Expression;
+6 -1
View File
@@ -7,6 +7,7 @@
#include <map>
#include <optional>
#include "explorer/ast/pattern.h"
#include "explorer/common/arena.h"
#include "explorer/common/error_builders.h"
#include "llvm/ADT/StringExtras.h"
@@ -184,7 +185,7 @@ void Expression::Print(llvm::raw_ostream& out) const {
}
case ExpressionKind::WhereExpression: {
const auto& where = cast<WhereExpression>(*this);
out << where.base() << " where ";
out << where.self_binding().type() << " where ";
llvm::ListSeparator sep(" and ");
for (const WhereClause* clause : where.clauses()) {
out << sep << *clause;
@@ -213,6 +214,7 @@ void Expression::Print(llvm::raw_ostream& out) const {
break;
}
case ExpressionKind::IdentifierExpression:
case ExpressionKind::DotSelfExpression:
case ExpressionKind::IntLiteral:
case ExpressionKind::BoolLiteral:
case ExpressionKind::BoolTypeLiteral:
@@ -232,6 +234,9 @@ void Expression::PrintID(llvm::raw_ostream& out) const {
case ExpressionKind::IdentifierExpression:
out << cast<IdentifierExpression>(*this).name();
break;
case ExpressionKind::DotSelfExpression:
out << ".Self";
break;
case ExpressionKind::IntLiteral:
out << cast<IntLiteral>(*this).value();
break;
+44 -5
View File
@@ -28,6 +28,7 @@ class MemberName;
class VariableType;
class InterfaceType;
class ImplBinding;
class GenericBinding;
class Expression : public AstNode {
public:
@@ -154,6 +155,40 @@ class IdentifierExpression : public Expression {
std::optional<ValueNodeView> value_node_;
};
// A `.Self` expression within either a `:!` binding or a standalone `where`
// expression.
//
// In a `:!` binding, the type of `.Self` is always `Type`. For example, in
// `A:! AddableWith(.Self)`, the expression `.Self` refers to the same type as
// `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`.
class DotSelfExpression : public Expression {
public:
explicit DotSelfExpression(SourceLocation source_loc)
: Expression(AstNodeKind::DotSelfExpression, source_loc) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromDotSelfExpression(node->kind());
}
// The self binding. Cannot be called before name resolution.
auto self_binding() const -> const GenericBinding& { return **self_binding_; }
auto self_binding() -> GenericBinding& { return **self_binding_; }
// Sets the self binding. Called only once, during name resolution.
void set_self_binding(Nonnull<GenericBinding*> self_binding) {
CARBON_CHECK(!self_binding_.has_value());
self_binding_ = self_binding;
}
private:
std::string name_;
std::optional<Nonnull<GenericBinding*>> self_binding_;
};
class SimpleMemberAccessExpression : public Expression {
public:
explicit SimpleMemberAccessExpression(SourceLocation source_loc,
@@ -741,20 +776,24 @@ class EqualsWhereClause : public WhereClause {
};
// A `where` expression: `AddableWith(i32) where .Result == i32`.
//
// The first operand is rewritten to a generic binding, for example
// `.Self:! AddableWith(i32)`, which may be used in the clauses.
class WhereExpression : public Expression {
public:
explicit WhereExpression(SourceLocation source_loc, Nonnull<Expression*> base,
explicit WhereExpression(SourceLocation source_loc,
Nonnull<GenericBinding*> self_binding,
std::vector<Nonnull<WhereClause*>> clauses)
: Expression(AstNodeKind::WhereExpression, source_loc),
base_(base),
self_binding_(self_binding),
clauses_(std::move(clauses)) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromWhereExpression(node->kind());
}
auto base() const -> const Expression& { return *base_; }
auto base() -> Expression& { return *base_; }
auto self_binding() const -> const GenericBinding& { return *self_binding_; }
auto self_binding() -> GenericBinding& { return *self_binding_; }
auto clauses() const -> llvm::ArrayRef<Nonnull<const WhereClause*>> {
return clauses_;
@@ -762,7 +801,7 @@ class WhereExpression : public Expression {
auto clauses() -> llvm::ArrayRef<Nonnull<WhereClause*>> { return clauses_; }
private:
Nonnull<Expression*> base_;
Nonnull<GenericBinding*> self_binding_;
std::vector<Nonnull<WhereClause*>> clauses_;
};
+16
View File
@@ -78,6 +78,12 @@ class Pattern : public AstNode {
// and after typechecking it's guaranteed to be true.
auto has_value() const -> bool { return value_.has_value(); }
// Determines whether the pattern has already been type-checked. Should
// only be used by type-checking.
auto is_type_checked() const -> bool {
return static_type_.has_value() && value_.has_value();
}
protected:
// Constructs a Pattern representing syntax at the given line number.
// `kind` must be the enumerator corresponding to the most-derived type being
@@ -277,12 +283,22 @@ class GenericBinding : public Pattern {
// Set the original generic binding.
void set_original(Nonnull<const GenericBinding*> orig) { original_ = orig; }
// Returns whether this binding has been named as a type within its own type
// expression via `.Self`. Set by type-checking.
auto named_as_type_via_dot_self() const -> bool {
return named_as_type_via_dot_self_;
}
// Set that this binding was named as a type within its own type expression
// via `.Self`. May only be called during type-checking.
void set_named_as_type_via_dot_self() { named_as_type_via_dot_self_ = true; }
private:
std::string name_;
Nonnull<Expression*> type_;
std::optional<Nonnull<const Value*>> symbolic_identity_;
std::optional<Nonnull<const ImplBinding*>> impl_binding_;
std::optional<Nonnull<const GenericBinding*>> original_;
bool named_as_type_via_dot_self_ = false;
};
// Converts paren_contents to a Pattern, interpreting the parentheses as
+2 -2
View File
@@ -163,7 +163,7 @@ class StaticScope {
// Make `parent` a parent of this scope.
// REQUIRES: `parent` is not already a parent of this scope.
void AddParent(Nonnull<StaticScope*> parent) {
void AddParent(Nonnull<const StaticScope*> parent) {
parent_scopes_.push_back(parent);
}
@@ -188,7 +188,7 @@ class StaticScope {
std::unordered_map<std::string, Entry> declared_names_;
// A list of scopes used for name lookup within this scope.
std::vector<Nonnull<StaticScope*>> parent_scopes_;
std::vector<Nonnull<const StaticScope*>> parent_scopes_;
};
} // namespace Carbon
+16 -1
View File
@@ -13,6 +13,7 @@
namespace Carbon {
using ::llvm::cast;
using ::llvm::isa;
static auto ExpressionToProto(const Expression& expression)
-> Fuzzing::Expression;
@@ -108,6 +109,13 @@ static auto ExpressionToProto(const Expression& expression)
case ExpressionKind::SimpleMemberAccessExpression: {
const auto& simple_member_access =
cast<SimpleMemberAccessExpression>(expression);
if (isa<DotSelfExpression>(simple_member_access.object())) {
// The parser rewrites `.Foo` into `.Self.Foo`. Undo this
// transformation.
auto* designator_proto = expression_proto.mutable_designator();
designator_proto->set_name(simple_member_access.member());
break;
}
auto* simple_member_access_proto =
expression_proto.mutable_simple_member_access();
simple_member_access_proto->set_field(simple_member_access.member());
@@ -182,7 +190,8 @@ static auto ExpressionToProto(const Expression& expression)
case ExpressionKind::WhereExpression: {
const auto& where = cast<WhereExpression>(expression);
auto* where_proto = expression_proto.mutable_where();
*where_proto->mutable_base() = ExpressionToProto(where.base());
*where_proto->mutable_base() =
ExpressionToProto(where.self_binding().type());
for (const WhereClause* where : where.clauses()) {
Fuzzing::WhereClause clause_proto;
switch (where->kind()) {
@@ -208,6 +217,12 @@ static auto ExpressionToProto(const Expression& expression)
break;
}
case ExpressionKind::DotSelfExpression: {
auto* designator_proto = expression_proto.mutable_designator();
designator_proto->set_name("Self");
break;
}
case ExpressionKind::IntrinsicExpression: {
const auto& intrinsic = cast<IntrinsicExpression>(expression);
auto* intrinsic_proto = expression_proto.mutable_intrinsic();
-3
View File
@@ -26,7 +26,6 @@ cc_library(
"//common:ostream",
"//explorer/ast:declaration",
"//explorer/ast:expression",
"//explorer/ast:pattern",
"//explorer/ast:statement",
"//explorer/common:arena",
"//explorer/common:error_builders",
@@ -141,7 +140,6 @@ cc_library(
"//explorer/ast",
"//explorer/ast:declaration",
"//explorer/ast:expression",
"//explorer/ast:pattern",
"//explorer/common:arena",
"//explorer/common:error_builders",
"@llvm-project//llvm:Support",
@@ -174,7 +172,6 @@ cc_library(
"//explorer/ast",
"//explorer/ast:declaration",
"//explorer/ast:expression",
"//explorer/ast:pattern",
"//explorer/ast:return_term",
"//explorer/ast:statement",
"//explorer/ast:static_scope",
+9
View File
@@ -408,6 +408,7 @@ auto Interpreter::StepLvalue() -> ErrorOr<Success> {
case ExpressionKind::IntrinsicExpression:
case ExpressionKind::IfExpression:
case ExpressionKind::WhereExpression:
case ExpressionKind::DotSelfExpression:
case ExpressionKind::ArrayTypeLiteral:
case ExpressionKind::InstantiateImpl:
CARBON_FATAL() << "Can't treat expression as lvalue: " << exp;
@@ -927,6 +928,14 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
}
return todo_.FinishAction(value);
}
case ExpressionKind::DotSelfExpression: {
// `.Self` always symbolically resolves to the self binding, even if it's
// not yet been type-checked.
CARBON_CHECK(act.pos() == 0);
const auto& dot_self = cast<DotSelfExpression>(exp);
return todo_.FinishAction(
arena_->New<VariableType>(&dot_self.self_binding()));
}
case ExpressionKind::IntLiteral:
CARBON_CHECK(act.pos() == 0);
// { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H}
+22 -9
View File
@@ -166,6 +166,15 @@ static auto ResolveNames(Expression& expression,
identifier.set_value_node(value_node);
break;
}
case ExpressionKind::DotSelfExpression: {
auto& dot_self = cast<DotSelfExpression>(expression);
CARBON_ASSIGN_OR_RETURN(
const auto value_node,
enclosing_scope.Resolve(".Self", dot_self.source_loc()));
dot_self.set_self_binding(const_cast<GenericBinding*>(
&cast<GenericBinding>(value_node.base())));
break;
}
case ExpressionKind::IntrinsicExpression:
CARBON_RETURN_IF_ERROR(ResolveNames(
cast<IntrinsicExpression>(expression).args(), enclosing_scope));
@@ -182,13 +191,14 @@ static auto ResolveNames(Expression& expression,
}
case ExpressionKind::WhereExpression: {
auto& where = cast<WhereExpression>(expression);
// TODO: Introduce `.Self` into scope?
// StaticScope where_scope;
// where_scope.AddParent(&enclosing_scope);
// where_scope.Add(".Self", ???);
CARBON_RETURN_IF_ERROR(ResolveNames(where.base(), enclosing_scope));
CARBON_RETURN_IF_ERROR(
ResolveNames(where.self_binding().type(), enclosing_scope));
// Introduce `.Self` into scope on the right of the `where` keyword.
StaticScope where_scope;
where_scope.AddParent(&enclosing_scope);
CARBON_RETURN_IF_ERROR(where_scope.Add(".Self", &where.self_binding()));
for (Nonnull<WhereClause*> clause : where.clauses()) {
CARBON_RETURN_IF_ERROR(ResolveNames(*clause, enclosing_scope));
CARBON_RETURN_IF_ERROR(ResolveNames(*clause, where_scope));
}
break;
}
@@ -253,7 +263,11 @@ static auto ResolveNames(Pattern& pattern, StaticScope& enclosing_scope)
}
case PatternKind::GenericBinding: {
auto& binding = cast<GenericBinding>(pattern);
CARBON_RETURN_IF_ERROR(ResolveNames(binding.type(), enclosing_scope));
// `.Self` is in scope in the context of the type.
StaticScope self_scope;
self_scope.AddParent(&enclosing_scope);
CARBON_RETURN_IF_ERROR(self_scope.Add(".Self", &binding));
CARBON_RETURN_IF_ERROR(ResolveNames(binding.type(), self_scope));
if (binding.name() != AnonymousName) {
CARBON_RETURN_IF_ERROR(enclosing_scope.Add(binding.name(), &binding));
}
@@ -425,8 +439,7 @@ static auto ResolveNames(Declaration& declaration, StaticScope& enclosing_scope)
StaticScope function_scope;
function_scope.AddParent(&enclosing_scope);
for (Nonnull<GenericBinding*> binding : function.deduced_parameters()) {
CARBON_RETURN_IF_ERROR(ResolveNames(binding->type(), function_scope));
CARBON_RETURN_IF_ERROR(function_scope.Add(binding->name(), binding));
CARBON_RETURN_IF_ERROR(ResolveNames(*binding, function_scope));
}
if (function.is_method()) {
CARBON_RETURN_IF_ERROR(
+40 -19
View File
@@ -757,11 +757,6 @@ class ConstraintTypeBuilder {
source_loc, ".Self", arena->New<TypeTypeLiteral>(source_loc))) {}
ConstraintTypeBuilder(Nonnull<const GenericBinding*> self_binding)
: self_binding_(self_binding) {}
ConstraintTypeBuilder(Nonnull<const ConstraintType*> constraint)
: self_binding_(constraint->self_binding()),
impl_constraints_(constraint->impl_constraints()),
equality_constraints_(constraint->equality_constraints()),
lookup_contexts_(constraint->lookup_contexts()) {}
// Produce a type that refers to the `.Self` type of the constraint.
auto MakeSelfType(Nonnull<Arena*> arena) const
@@ -1090,8 +1085,6 @@ auto TypeChecker::MatchImpl(const InterfaceType& iface,
return std::nullopt;
}
// TODO: If the `interface` is a ConstraintType, for every impl_constraint,
// try deduction against that.
if (ErrorOr<Success> e = ArgumentDeduction(
source_loc, "match", impl.deduced, deduced_args, impl.interface,
&iface, /*allow_implicit_conversion=*/false, impl_scope);
@@ -1259,6 +1252,8 @@ auto TypeChecker::DeduceCallBindings(
impl_bindings, impl_scope, call.source_loc(), generic_bindings, impls));
call.set_impls(impls);
// TODO: Ensure any equality constraints are satisfied.
// Convert the arguments to the parameter type.
Nonnull<const Value*> param_type = Substitute(generic_bindings, params_type);
CARBON_ASSIGN_OR_RETURN(
@@ -1778,6 +1773,17 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
ident.set_value_category(ident.value_node().value_category());
return Success();
}
case ExpressionKind::DotSelfExpression: {
auto& dot_self = cast<DotSelfExpression>(*e);
if (dot_self.self_binding().is_type_checked()) {
dot_self.set_static_type(&dot_self.self_binding().static_type());
} else {
dot_self.set_static_type(arena_->New<TypeType>());
dot_self.self_binding().set_named_as_type_via_dot_self();
}
dot_self.set_value_category(ValueCategory::Let);
return Success();
}
case ExpressionKind::IntLiteral:
e->set_value_category(ValueCategory::Let);
e->set_static_type(arena_->New<IntType>());
@@ -2074,28 +2080,38 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
}
case ExpressionKind::WhereExpression: {
auto& where = cast<WhereExpression>(*e);
CARBON_RETURN_IF_ERROR(TypeCheckExp(&where.base(), impl_scope));
ImplScope inner_impl_scope;
inner_impl_scope.AddParent(&impl_scope);
CARBON_RETURN_IF_ERROR(TypeCheckPattern(&where.self_binding(),
std::nullopt, inner_impl_scope,
ValueCategory::Let));
for (Nonnull<WhereClause*> clause : where.clauses()) {
CARBON_RETURN_IF_ERROR(TypeCheckWhereClause(clause, impl_scope));
CARBON_RETURN_IF_ERROR(TypeCheckWhereClause(clause, inner_impl_scope));
}
const ConstraintType* base;
const Value& base_type = where.base().static_type();
if (auto* constraint_type_type =
dyn_cast<TypeOfConstraintType>(&base_type)) {
base = &constraint_type_type->constraint_type();
} else if (auto* interface_type_type =
dyn_cast<TypeOfInterfaceType>(&base_type)) {
base = MakeConstraintForInterface(
e->source_loc(), &interface_type_type->interface_type());
std::optional<Nonnull<const ConstraintType*>> base;
const Value& base_type = where.self_binding().static_type();
if (auto* constraint_type = dyn_cast<ConstraintType>(&base_type)) {
base = constraint_type;
} else if (auto* interface_type = dyn_cast<InterfaceType>(&base_type)) {
base = MakeConstraintForInterface(e->source_loc(), interface_type);
} else if (isa<TypeType>(base_type)) {
// Start with an unconstrained type.
} else {
return CompilationError(e->source_loc())
<< "expected constraint as first operand of `where` expression, "
<< "found " << base_type;
}
// Start with the given constraint, if any.
ConstraintTypeBuilder builder(&where.self_binding());
if (base) {
BindingMap map;
map[(*base)->self_binding()] = builder.MakeSelfType(arena_);
builder.Add(cast<ConstraintType>(Substitute(map, *base)));
}
// Apply the `where` clauses.
ConstraintTypeBuilder builder(base);
for (Nonnull<const WhereClause*> clause : where.clauses()) {
switch (clause->kind()) {
case WhereClauseKind::IsWhereClause: {
@@ -2340,6 +2356,11 @@ auto TypeChecker::TypeCheckPattern(
<< binding;
}
binding.set_static_type(type);
if (binding.named_as_type_via_dot_self() && !IsTypeOfType(type)) {
return CompilationError(binding.type().source_loc())
<< "`.Self` used in type of non-type binding `" << binding.name()
<< "`";
}
CARBON_ASSIGN_OR_RETURN(Nonnull<const Value*> val,
InterpPattern(&binding, arena_, trace_stream_));
binding.set_symbolic_identity(val);
-1
View File
@@ -81,7 +81,6 @@ cc_library(
"//explorer/ast:declaration",
"//explorer/ast:expression",
"//explorer/ast:paren_contents",
"//explorer/ast:pattern",
"//explorer/ast:value_category",
"//explorer/common:arena",
"//explorer/common:error_builders",
+14 -1
View File
@@ -301,6 +301,15 @@ api_or_impl:
primary_expression:
identifier
{ $$ = arena->New<IdentifierExpression>(context.source_loc(), $1); }
| designator
{
// `.Foo` is rewritten to `.Self.Foo`.
$$ = arena->New<SimpleMemberAccessExpression>(
context.source_loc(),
arena->New<DotSelfExpression>(context.source_loc()), $1);
}
| PERIOD SELF
{ $$ = arena->New<DotSelfExpression>(context.source_loc()); }
| integer_literal
{ $$ = arena->New<IntLiteral>(context.source_loc(), $1); }
| string_literal
@@ -544,7 +553,11 @@ where_clause_list:
;
where_expression:
type_expression WHERE where_clause_list
{ $$ = arena->New<WhereExpression>(context.source_loc(), $1, $3); }
{
auto* self =
arena -> New<GenericBinding>(context.source_loc(), ".Self", $1);
$$ = arena->New<WhereExpression>(context.source_loc(), self, $3);
}
;
statement_expression:
ref_deref_expression
+30
View File
@@ -0,0 +1,30 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// RUN: %{explorer} %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
// RUN: %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s
// AUTOUPDATE: %{explorer} %s
// CHECK: result: 12
package ExplorerTest api;
interface SwizzleWith(T:! Type) {
fn Op[me: Self](x: T) -> i32;
}
impl i32 as SwizzleWith(i32) {
fn Op[me: Self](x: Self) -> Self { return me * 10 + x; }
}
fn F[T:! SwizzleWith(.Self)](v: T, w: T) -> i32 {
return v.Op(w);
}
fn Main() -> i32 {
var one: i32 = 1;
var two: i32 = 2;
return F(one, two);
}
+1 -1
View File
@@ -15,7 +15,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: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/combine_equality.carbon:[[@LINE+1]]: member access, F not in constraint interface I where .Self:! Type is interface I, A:! i32 == B:! i32 == E:! i32 == C:! i32 == D:! i32
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/combine_equality.carbon:[[@LINE+1]]: member access, F not in constraint interface I where .Self:! I is interface I, A:! i32 == B:! i32 == E:! i32 == C:! i32 == D:! i32
T.F();
}
+31
View File
@@ -0,0 +1,31 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// RUN: %{explorer} %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
// RUN: %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s
// AUTOUPDATE: %{explorer} %s
// CHECK: result: 12
package ExplorerTest api;
interface A { fn F() -> i32; }
interface B { fn F() -> i32; }
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 {
// 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.
return 10 * GetA(x) + x.F();
}
fn Main() -> i32 {
var v: i32 = 0;
return GetAB(v);
}
@@ -0,0 +1,22 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// RUN: %{not} %{explorer} %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
// RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s
// AUTOUPDATE: %{explorer} %s
package ExplorerTest api;
interface FrobWith(T:! Type) {}
fn F[T:! FrobWith(.Self)]
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/fail_dot_self_after_scope.carbon:[[@LINE+1]]: could not resolve '.Self'
(U: .Self) {
}
fn Main() -> i32 {
return 0;
}
@@ -0,0 +1,22 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// RUN: %{not} %{explorer} %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
// RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s
// AUTOUPDATE: %{explorer} %s
package ExplorerTest api;
interface FrobWith(T:! Type) {}
fn F[T:! FrobWith(.Self),
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/fail_dot_self_after_scope_2.carbon:[[@LINE+1]]: `.Self` used in type of non-type binding `U`
U:! .Self]() {
}
fn Main() -> i32 {
return 0;
}
@@ -0,0 +1,16 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// RUN: %{not} %{explorer} %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
// RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s
// AUTOUPDATE: %{explorer} %s
package ExplorerTest api;
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/fail_dot_self_not_in_scope.carbon:[[@LINE+1]]: could not resolve '.Self'
fn Main() -> .Self {
return 0;
}
+16
View File
@@ -0,0 +1,16 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// RUN: %{not} %{explorer} %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
// RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s
// AUTOUPDATE: %{explorer} %s
package ExplorerTest api;
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/fail_infinite_self.carbon:[[@LINE+1]]: `.Self` used in type of non-type binding `T`
fn F[T:! .Self]() {}
fn Main() -> i32 { return 0; }
@@ -0,0 +1,16 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// RUN: %{not} %{explorer} %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
// RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s
// AUTOUPDATE: %{explorer} %s
package ExplorerTest api;
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/fail_infinite_self_ptr.carbon:[[@LINE+1]]: `.Self` used in type of non-type binding `T`
fn F[T:! .Self*]() {}
fn Main() -> i32 { return 0; }
+18
View File
@@ -0,0 +1,18 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// RUN: %{not} %{explorer} %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
// RUN: %{not} %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s
// AUTOUPDATE: %{explorer} %s
package ExplorerTest api;
class X(T:! Type) {}
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/constraint/fail_nontype_self.carbon:[[@LINE+1]]: `.Self` used in type of non-type binding `T`
fn F[T:! X(.Self)](x: T) {}
fn Main() -> i32 { return 0; }
@@ -0,0 +1,26 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// RUN: %{explorer} %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
// RUN: %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s
// AUTOUPDATE: %{explorer} %s
// CHECK: result: 122
package ExplorerTest api;
interface A { fn F() -> i32; }
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 {
return 100 * T.(A.F)() + 10 * T.(B.F)() + T.F();
}
fn Main() -> i32 {
return GetAB(i32);
}
+34
View File
@@ -0,0 +1,34 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// RUN: %{explorer} %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
// RUN: %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s
// AUTOUPDATE: %{explorer} %s
// CHECK: result: 12
package ExplorerTest api;
interface SwizzleWith(T:! Type) {
fn Op[me: Self](x: T) -> i32;
}
// 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);
impl i32 as SwizzleWith(i32) {
fn Op[me: Self](x: Self) -> Self { return me * 10 + x; }
}
fn F[T:! Swizzle](v: T, w: T) -> i32 {
return v.(SwizzleWith(T).Op)(w);
}
fn Main() -> i32 {
var one: i32 = 1;
var two: i32 = 2;
return F(one, two);
}