Provide an alternative to requesting if an expression has inout type

To remove some callers of 'is<InOutType>' after Sema, start using what will soon be a structural invariant - the only expressions that can possibly have 'inout' type are semantically InOut expressions.
This commit is contained in:
Robert Widmann
2017-07-11 14:23:04 -07:00
parent c8a1e5e9ec
commit 5d5d16393c
5 changed files with 72 additions and 34 deletions

View File

@@ -4385,10 +4385,7 @@ public:
/// Get the type of the variable within its context. If the context is generic,
/// this will use archetypes.
Type getType() const {
assert(!typeInContext.isNull() && "no contextual type set yet");
return typeInContext;
}
Type getType() const;
/// Set the type of the variable within its context.
void setType(Type t);
@@ -4577,7 +4574,7 @@ public:
ParameterTypeFlags getParameterFlags() const;
SourceLoc getSpecifierLoc() const { return SpecifierLoc; }
bool isTypeLocImplicit() const { return IsTypeLocImplicit; }
void setIsTypeLocImplicit(bool val) { IsTypeLocImplicit = val; }

View File

@@ -592,6 +592,15 @@ public:
/// a base class.
bool isSuperExpr() const;
/// Returns whether the semantically meaningful content of this expression is
/// an inout expression.
///
/// FIXME(Remove InOutType): This should eventually sub-in for
/// 'E->getType()->is<InOutType>()' in all cases.
bool isSemanticallyInOutExpr() const {
return getSemanticsProvidingExpr()->getKind() == ExprKind::InOut;
}
/// Returns false if this expression needs to be wrapped in parens when
/// used inside of a any postfix expression, true otherwise.
///
@@ -3241,10 +3250,8 @@ class InOutExpr : public Expr {
SourceLoc OperLoc;
public:
InOutExpr(SourceLoc operLoc, Expr *subExpr, Type type,
bool isImplicit = false)
: Expr(ExprKind::InOut, isImplicit, type),
SubExpr(subExpr), OperLoc(operLoc) {}
InOutExpr(SourceLoc operLoc, Expr *subExpr, Type baseType,
bool isImplicit = false);
SourceLoc getStartLoc() const { return OperLoc; }
SourceLoc getEndLoc() const { return SubExpr->getEndLoc(); }

View File

@@ -946,14 +946,12 @@ FuncDecl *ASTContext::getArrayAppendElementDecl() const {
return nullptr;
if (ParamLists[0]->size() != 1)
return nullptr;
InOutType *SelfInOutTy =
ParamLists[0]->get(0)->getInterfaceType()->getAs<InOutType>();
if (!SelfInOutTy)
if (!ParamLists[0]->get(0)->isInOut())
return nullptr;
auto SelfInOutTy = ParamLists[0]->get(0)->getInterfaceType();
BoundGenericStructType *SelfGenericStructTy =
SelfInOutTy->getObjectType()->getAs<BoundGenericStructType>();
SelfInOutTy->getInOutObjectType()->getAs<BoundGenericStructType>();
if (!SelfGenericStructTy)
return nullptr;
if (SelfGenericStructTy->getDecl() != getArrayDecl())
@@ -997,14 +995,12 @@ FuncDecl *ASTContext::getArrayReserveCapacityDecl() const {
return nullptr;
if (ParamLists[0]->size() != 1)
return nullptr;
InOutType *SelfInOutTy =
ParamLists[0]->get(0)->getInterfaceType()->getAs<InOutType>();
if (!SelfInOutTy)
if (!ParamLists[0]->get(0)->isInOut())
return nullptr;
auto SelfInOutTy = ParamLists[0]->get(0)->getInterfaceType();
BoundGenericStructType *SelfGenericStructTy =
SelfInOutTy->getObjectType()->getAs<BoundGenericStructType>();
SelfInOutTy->getInOutObjectType()->getAs<BoundGenericStructType>();
if (!SelfGenericStructTy)
return nullptr;
if (SelfGenericStructTy->getDecl() != getArrayDecl())
@@ -2665,13 +2661,18 @@ BuiltinVectorType *BuiltinVectorType::get(const ASTContext &context,
ParenType *ParenType::get(const ASTContext &C, Type underlying,
ParameterTypeFlags fl) {
auto flags = fl.withInOut(underlying->is<InOutType>());
if (fl.isInOut())
assert(!underlying->is<InOutType>() && "caller did not pass a base type");
if (underlying->is<InOutType>())
assert(fl.isInOut() && "caller did not set flags correctly");
auto properties = underlying->getRecursiveProperties();
auto arena = getArena(properties);
ParenType *&Result =
C.Impl.getArena(arena).ParenTypes[{underlying, flags.toRaw()}];
C.Impl.getArena(arena).ParenTypes[{underlying, fl.toRaw()}];
if (Result == nullptr) {
Result = new (C, arena) ParenType(underlying, properties, flags);
Result = new (C, arena) ParenType(underlying,
properties, fl);
}
return Result;
}
@@ -2693,7 +2694,7 @@ void TupleType::Profile(llvm::FoldingSetNodeID &ID,
/// getTupleType - Return the uniqued tuple type with the specified elements.
Type TupleType::get(ArrayRef<TupleTypeElt> Fields, const ASTContext &C) {
if (Fields.size() == 1 && !Fields[0].isVararg() && !Fields[0].hasName())
return ParenType::get(C, Fields[0].getType(),
return ParenType::get(C, Fields[0].getRawType(),
Fields[0].getParameterFlags());
RecursiveTypeProperties properties;
@@ -2703,7 +2704,7 @@ Type TupleType::get(ArrayRef<TupleTypeElt> Fields, const ASTContext &C) {
if (!eltTy) continue;
properties |= eltTy->getRecursiveProperties();
hasInOut |= eltTy->is<InOutType>();
hasInOut |= Elt.getParameterFlags().isInOut();
}
auto arena = getArena(properties);
@@ -2740,10 +2741,38 @@ Type TupleType::get(ArrayRef<TupleTypeElt> Fields, const ASTContext &C) {
TupleTypeElt::TupleTypeElt(Type ty, Identifier name,
ParameterTypeFlags fl)
: Name(name), ElementType(ty), Flags(fl.withInOut(ty->is<InOutType>())) {
// FIXME: Re-enable this assertion and hunt down the callers that aren't
// setting parameter bits correctly.
// assert((ty->is<InOutType>() && fl.isInOut()) && "caller did not set flags");
: Name(name), ElementType(ty), Flags(fl) {
if (fl.isInOut())
assert(!ty->is<InOutType>() && "caller did not pass a base type");
if (ty->is<InOutType>())
assert(fl.isInOut() && "caller did not set flags correctly");
}
Type TupleTypeElt::getType() const {
if (Flags.isInOut()) return InOutType::get(ElementType);
return ElementType;
}
AnyFunctionType::Param::Param(const TupleTypeElt &tte)
: Ty(tte.isVararg() ? tte.getVarargBaseTy() : tte.getRawType()),
Label(tte.getName()), Flags(tte.getParameterFlags()) {
assert(getType()->is<InOutType>() == Flags.isInOut());
}
AnyFunctionType::Param::Param(Type t, Identifier l, ParameterTypeFlags f)
: Ty(t), Label(l), Flags(f) {
if (f.isInOut())
assert(!t->is<InOutType>() && "caller did not pass a base type");
if (!t.isNull() && t->is<InOutType>())
assert(f.isInOut() && "caller did not set flags correctly");
}
Type AnyFunctionType::Param::getType() const {
if (Flags.isInOut()) return InOutType::get(Ty);
// FIXME: Callers are inconsistenly setting this flag and retrieving this
// type with and without the Array Slice type.
// if (Flags.isVariadic()) return ArraySliceType::get(Ty);
return Ty;
}
void UnboundGenericType::Profile(llvm::FoldingSetNodeID &ID,
@@ -3176,13 +3205,18 @@ void AnyFunctionType::decomposeInput(
}
case TypeKind::Paren: {
auto ty = cast<ParenType>(type.getPointer())->getUnderlyingType();
result.push_back(AnyFunctionType::Param(ty));
auto pty = cast<ParenType>(type.getPointer());
result.push_back(AnyFunctionType::Param(pty->getUnderlyingType()->getInOutObjectType(),
Identifier(),
pty->getParameterFlags()));
return;
}
default:
result.push_back(AnyFunctionType::Param(type));
// assert(type->is<InOutType>() && "Found naked inout type");
result.push_back(AnyFunctionType::Param(type->getInOutObjectType(),
Identifier(),
ParameterTypeFlags::fromParameterType(type, false)));
return;
}
}
@@ -3191,7 +3225,7 @@ Type AnyFunctionType::composeInput(ASTContext &ctx, ArrayRef<Param> params,
bool canonicalVararg) {
SmallVector<TupleTypeElt, 4> elements;
for (const auto &param : params) {
Type eltType = param.getType();
Type eltType = param.getRawType();
if (param.isVariadic()) {
if (canonicalVararg)
eltType = BoundGenericType::get(ctx.getArrayDecl(), Type(), {eltType});

View File

@@ -183,7 +183,7 @@ ManagedValue ArgumentSource::getAsSingleValue(SILGenFunction &SGF,
}
case Kind::Expr: {
auto e = std::move(*this).asKnownExpr();
if (e->getType()->is<InOutType>()) {
if (e->isSemanticallyInOutExpr()) {
return SGF.emitAddressOfLValue(e, SGF.emitLValue(e, AccessKind::ReadWrite),
AccessKind::ReadWrite);
} else {

View File

@@ -194,7 +194,7 @@ public:
case Kind::Invalid: llvm_unreachable("argument source is invalid");
case Kind::RValue: return false;
case Kind::LValue: return true;
case Kind::Expr: return asKnownExpr()->getType()->is<InOutType>();
case Kind::Expr: return asKnownExpr()->isSemanticallyInOutExpr();
case Kind::Tuple: return false;
}
llvm_unreachable("bad kind");