static bool diagnoseUnwrap(ConstraintSystem &CS, Expr *expr, Type type) { Type unwrappedType = type->getOptionalObjectType(); if (!unwrappedType) return false; CS.TC.diagnose(expr->getLoc(), diag::optional_not_unwrapped, type, unwrappedType); // If the expression we're unwrapping is the only reference to a // local variable whose type isn't explicit in the source, then // offer unwrapping fixits on the initializer as well. if (auto declRef = dyn_cast<DeclRefExpr>(expr)) { if (auto varDecl = dyn_cast<VarDecl>(declRef->getDecl())) { bool singleUse = false; AbstractFunctionDecl *AFD = nullptr; if (auto contextDecl = varDecl->getDeclContext()->getAsDecl()) { if ((AFD = dyn_cast<AbstractFunctionDecl>(contextDecl))) { auto checker = VarDeclMultipleReferencesChecker(varDecl); AFD->getBody()->walk(checker); singleUse = checker.referencesCount() == 1; } } PatternBindingDecl *binding = varDecl->getParentPatternBinding(); if (singleUse && binding && binding->getNumPatternEntries() == 1 && varDecl->getTypeSourceRangeForDiagnostics().isInvalid()) { Expr *initializer = varDecl->getParentInitializer(); if (auto declRefExpr = dyn_cast<DeclRefExpr>(initializer)) { if (declRefExpr->getDecl()->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>()) { CS.TC.diagnose(declRefExpr->getLoc(), diag::unwrap_iuo_initializer, type); } } auto fnTy = AFD->getInterfaceType()->castTo<AnyFunctionType>(); bool voidReturn = fnTy->getResult()->isEqual(TupleType::getEmpty(CS.DC->getASTContext())); auto diag = CS.TC.diagnose(varDecl->getLoc(), diag::unwrap_with_guard); diag.fixItInsert(binding->getStartLoc(), "guard "); if (voidReturn) { diag.fixItInsertAfter(binding->getEndLoc(), " else { return }"); } else { diag.fixItInsertAfter(binding->getEndLoc(), " else { return <" "#default value#" "> }"); } diag.flush(); offerDefaultValueUnwrapFixit(CS.TC, varDecl->getDeclContext(), initializer); offerForceUnwrapFixit(CS, initializer); } } } offerDefaultValueUnwrapFixit(CS.TC, CS.DC, expr); offerForceUnwrapFixit(CS, expr); return true; }
/// When we see an expression in a TopLevelCodeDecl in the REPL, process it, /// adding the proper decls back to the top level of the file. void REPLChecker::processREPLTopLevelExpr(Expr *E) { CanType T = E->getType()->getCanonicalType(); // Don't try to print invalid expressions, module exprs, or void expressions. if (T->hasError() || isa<ModuleType>(T) || T->isVoid()) return; // Okay, we need to print this expression. We generally do this by creating a // REPL metavariable (e.g. r4) to hold the result, so it can be referred to // in the future. However, if this is a direct reference to a decl (e.g. "x") // then don't create a repl metavariable. if (VarDecl *d = getObviousDeclFromExpr(E)) { generatePrintOfExpression(d->getName().str(), E); return; } // Remove the expression from being in the list of decls to execute, we're // going to reparent it. auto TLCD = cast<TopLevelCodeDecl>(SF.Decls.back()); E = TC.coerceToRValue(E); // Create the meta-variable, let the typechecker name it. Identifier name = TC.getNextResponseVariableName(SF.getParentModule()); VarDecl *vd = new (Context) VarDecl(/*IsStatic*/false, VarDecl::Specifier::Let, /*IsCaptureList*/false, E->getStartLoc(), name, E->getType(), &SF); vd->setInterfaceType(E->getType()); SF.Decls.push_back(vd); // Create a PatternBindingDecl to bind the expression into the decl. Pattern *metavarPat = new (Context) NamedPattern(vd); metavarPat->setType(E->getType()); PatternBindingDecl *metavarBinding = PatternBindingDecl::create( Context, /*StaticLoc*/ SourceLoc(), StaticSpellingKind::None, /*VarLoc*/ E->getStartLoc(), metavarPat, /*EqualLoc*/ SourceLoc(), E, TLCD); // Overwrite the body of the existing TopLevelCodeDecl. TLCD->setBody(BraceStmt::create(Context, metavarBinding->getStartLoc(), ASTNode(metavarBinding), metavarBinding->getEndLoc(), /*implicit*/true)); // Finally, print the variable's value. E = TC.buildCheckedRefExpr(vd, &SF, DeclNameLoc(E->getStartLoc()), /*Implicit=*/true); generatePrintOfExpression(vd->getName().str(), E); }
/// processREPLTopLevelPatternBinding - When we see a new PatternBinding parsed /// into the REPL, process it by generating code to print it out. void REPLChecker::processREPLTopLevelPatternBinding(PatternBindingDecl *PBD) { // If there is no initializer for the new variable, don't auto-print it. // This would just cause a confusing definite initialization error. Some // day we will do some high level analysis of uninitialized variables // (rdar://15157729) but until then, output a specialized error. unsigned entryIdx = 0U-1; for (auto patternEntry : PBD->getPatternList()) { ++entryIdx; if (!patternEntry.getInit()) { TC.diagnose(PBD->getStartLoc(), diag::repl_must_be_initialized); continue; } auto pattern = patternEntry.getPattern(); llvm::SmallString<16> PatternString; PatternBindingPrintLHS(PatternString).visit(pattern); // If the bound pattern is a single value, use a DeclRefExpr on the // underlying Decl to print it. if (auto *NP = dyn_cast<NamedPattern>(pattern-> getSemanticsProvidingPattern())) { Expr *E = TC.buildCheckedRefExpr(NP->getDecl(), &SF, PBD->getStartLoc(), /*Implicit=*/true); generatePrintOfExpression(PatternString, E); continue; } // Otherwise, we may not have a way to name all of the pieces of the pattern. // Create a repl metavariable to capture the whole thing so we can reference // it, then assign that into the pattern. For example, translate: // var (x, y, _) = foo() // into: // var r123 = foo() // var (x, y, _) = r123 // replPrint(r123) // Remove PBD from the list of Decls so we can insert before it. auto PBTLCD = cast<TopLevelCodeDecl>(SF.Decls.back()); SF.Decls.pop_back(); // Create the meta-variable, let the typechecker name it. Identifier name = TC.getNextResponseVariableName(SF.getParentModule()); VarDecl *vd = new (Context) VarDecl(/*static*/ false, /*IsLet*/true, PBD->getStartLoc(), name, pattern->getType(), &SF); SF.Decls.push_back(vd); // Create a PatternBindingDecl to bind the expression into the decl. Pattern *metavarPat = new (Context) NamedPattern(vd); metavarPat->setType(vd->getType()); PatternBindingDecl *metavarBinding = PatternBindingDecl::create(Context, SourceLoc(), StaticSpellingKind::None, PBD->getStartLoc(), metavarPat, patternEntry.getInit(), &SF); auto MVBrace = BraceStmt::create(Context, metavarBinding->getStartLoc(), ASTNode(metavarBinding), metavarBinding->getEndLoc()); auto *MVTLCD = new (Context) TopLevelCodeDecl(&SF, MVBrace); SF.Decls.push_back(MVTLCD); // Replace the initializer of PBD with a reference to our repl temporary. Expr *E = TC.buildCheckedRefExpr(vd, &SF, vd->getStartLoc(), /*Implicit=*/true); E = TC.coerceToMaterializable(E); PBD->setInit(entryIdx, E); SF.Decls.push_back(PBTLCD); // Finally, print out the result, by referring to the repl temp. E = TC.buildCheckedRefExpr(vd, &SF, vd->getStartLoc(), /*Implicit=*/true); generatePrintOfExpression(PatternString, E); } }