Skip to content

Commit

Permalink
Handle simple cases of T* sugar in expressions, where * is infix.
Browse files Browse the repository at this point in the history
More of <rdar://problem/16912508>.


Swift SVN r18209
  • Loading branch information
DougGregor committed May 16, 2014
1 parent fed3b6d commit db38b64
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 14 deletions.
12 changes: 1 addition & 11 deletions lib/Sema/TypeCheckConstraints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -539,16 +539,6 @@ bool PreCheckExpression::walkToClosureExprPre(ClosureExpr *closure) {
return true;
}

static bool isAsteriskRef(Expr *E) {
if (auto UDRE = dyn_cast<UnresolvedDeclRefExpr>(E))
return UDRE->getName().str() == "*";
if (auto DRE = dyn_cast<DeclRefExpr>(E))
return DRE->getDecl()->getName().str() == "*";
if (auto ODRE = dyn_cast<OverloadedDeclRefExpr>(E))
return ODRE->getDecls()[0]->getName().str() == "*";
return false;
}

/// Simplify expressions which are type sugar productions that got parsed
/// as expressions due to the parser not knowing which identifiers are
/// type names.
Expand Down Expand Up @@ -603,7 +593,7 @@ TypeExpr *PreCheckExpression::simplifyTypeExpr(Expr *E) {
auto *TyExpr = dyn_cast<TypeExpr>(PUE->getArg());
if (!TyExpr) return nullptr;

if (!isAsteriskRef(PUE->getFn()))
if (!TypeChecker::isAsteriskRef(PUE->getFn()))
return nullptr;

auto *InnerTypeRepr = TyExpr->getTypeRepr();
Expand Down
41 changes: 40 additions & 1 deletion lib/Sema/TypeCheckExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,16 @@ static Expr *makeBinOp(TypeChecker &TC, Expr *Op, Expr *LHS, Expr *RHS) {
return new (TC.Context) BinaryExpr(Op, Arg, Op->isImplicit());
}

bool TypeChecker::isAsteriskRef(Expr *E) {
if (auto UDRE = dyn_cast<UnresolvedDeclRefExpr>(E))
return UDRE->getName().str() == "*";
if (auto DRE = dyn_cast<DeclRefExpr>(E))
return DRE->getDecl()->getName().str() == "*";
if (auto ODRE = dyn_cast<OverloadedDeclRefExpr>(E))
return ODRE->getDecls()[0]->getName().str() == "*";
return false;
}

/// foldSequence - Take a sequence of expressions and fold a prefix of
/// it into a tree of BinaryExprs using precedence parsing.
static Expr *foldSequence(TypeChecker &TC, DeclContext *DC,
Expand Down Expand Up @@ -267,12 +277,41 @@ static Expr *foldSequence(TypeChecker &TC, DeclContext *DC,
// Extract out the first operator.
Op Op1 = getNextOperator();
if (!Op1) return LHS;

// We will definitely be consuming at least one operator.
// Pull out the prospective RHS and slice off the first two elements.
Expr *RHS = S[1];
S = S.slice(2);

// If the LHS is a TypeExpr and the operator is a '*', this is an
// unsafe pointer. If the RHS is something that would have been
// handled as postfix, handle it now.
if (isa<TypeExpr>(LHS) && TypeChecker::isAsteriskRef(Op1.op)) {
// Local function that forms an unsafe pointer TypeExpr.
auto formUnsafePointerRef = [&](TypeExpr *Base, Expr *Op) -> TypeExpr * {
auto *InnerTypeRepr = Base->getTypeRepr();
auto *NewTypeRepr
= new (TC.Context) UnsafePointerTypeRepr(InnerTypeRepr, Op->getLoc());
return new (TC.Context) TypeExpr(TypeLoc(NewTypeRepr, Type()));
};

// If the right-hand side is a tuple or parentheses, we're
// constructing an unsafe pointer.
// FIXME: Check that the start of the parentheses isn't on a new line.
if (isa<TupleExpr>(RHS) || isa<ParenExpr>(RHS)) {
LHS = formUnsafePointerRef(cast<TypeExpr>(LHS), Op1.op);
LHS = new (TC.Context) CallExpr(LHS, RHS, /*Implicit=*/false);
if (S.empty())
return LHS;

Op1 = getNextOperator();
if (!Op1) return LHS;
}

// FIXME: More cases we should be able to handle, e.g.,
// subscripting.
}

while (!S.empty()) {
assert(!S.empty());
assert((S.size() & 1) == 0);
Expand Down
3 changes: 3 additions & 0 deletions lib/Sema/TypeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,9 @@ class TypeChecker : public LazyResolver {
void fillObjCRepresentableTypeCache(const DeclContext *DC);

ArchetypeBuilder createArchetypeBuilder(Module *mod);

/// Determine whether this is a reference to the '*' operator.
static bool isAsteriskRef(Expr *expr);
};

} // end namespace swift
Expand Down
15 changes: 13 additions & 2 deletions test/type/types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,21 @@ func test_optional_construct<T>() {
var c = (Int?)() // Parenthesized name.
}

// postfix * as sugar in expressions,
// postfix * as sugar in expressions.
func test_unsafe_pointer_construct_postfix<T>(t: T) {
var a = T* ()
var b = (T*)()
}

// FIXME: * is infix is a delight
// infix * as sugar in expressions.
func test_unsafe_pointer_construct_infix<T>(t: T) {
var a = T*()
var b = T*(5)
var c = T*.null()
var d = T* * (5)

a.pointee = t
b.pointee = t
c.pointee = t
d.pointee = T*(5)
}

0 comments on commit db38b64

Please sign in to comment.