diff --git a/src/fsharp/CheckComputationExpressions.fs b/src/fsharp/CheckComputationExpressions.fs index 762fe323d73..e93ac847098 100644 --- a/src/fsharp/CheckComputationExpressions.fs +++ b/src/fsharp/CheckComputationExpressions.fs @@ -213,8 +213,9 @@ let RecordNameAndTypeResolutions_IdeallyWithoutHavingOtherEffects cenv env tpenv with e -> ()) /// Used for all computation expressions except sequence expressions -let TcComputationExpression cenv env overallTy tpenv (mWhole, interpExpr: Expr, builderTy, comp: SynExpr) = - +let TcComputationExpression cenv env (overallTy: OverallTy) tpenv (mWhole, interpExpr: Expr, builderTy, comp: SynExpr) = + let overallTy = overallTy.Commit + //dprintfn "TcComputationExpression, comp = \n%A\n-------------------\n" comp let ad = env.eAccessRights @@ -1642,7 +1643,7 @@ let TcComputationExpression cenv env overallTy tpenv (mWhole, interpExpr: Expr, | SynExpr.YieldOrReturn ((_, true), _, _) -> { env with eContextInfo = ContextInfo.ReturnInComputationExpression } | _ -> env - let lambdaExpr, tpenv= TcExpr cenv (builderTy --> overallTy) env tpenv lambdaExpr + let lambdaExpr, tpenv= TcExpr cenv (MustEqual (builderTy --> overallTy)) env tpenv lambdaExpr // beta-var-reduce to bind the builder using a 'let' binding let coreExpr = mkApps cenv.g ((lambdaExpr, tyOfExpr cenv.g lambdaExpr), [], [interpExpr], mBuilderVal) @@ -1704,10 +1705,10 @@ let compileSeqExprMatchClauses (cenv: cenv) env inputExprMark (pat: Pattern, vsp /// These are later detected by state machine compilation. /// /// Also "ienumerable extraction" is performed on arguments to "for". -let TcSequenceExpression (cenv: cenv) env tpenv comp overallTy m = +let TcSequenceExpression (cenv: cenv) env tpenv comp (overallTy: OverallTy) m = let genEnumElemTy = NewInferenceType () - UnifyTypes cenv env m overallTy (mkSeqTy cenv.g genEnumElemTy) + UnifyTypes cenv env m overallTy.Commit (mkSeqTy cenv.g genEnumElemTy) // Allow subsumption at 'yield' if the element type is nominal prior to the analysis of the body of the sequence expression let flex = not (isTyparTy cenv.g genEnumElemTy) @@ -1765,7 +1766,7 @@ let TcSequenceExpression (cenv: cenv) env tpenv comp overallTy m = Some(tcSequenceExprBody env genOuterTy tpenv (elimFastIntegerForLoop (spBind, id, start, dir, finish, innerComp, m))) | SynExpr.While (spWhile, guardExpr, innerComp, _m) -> - let guardExpr, tpenv = TcExpr cenv cenv.g.bool_ty env tpenv guardExpr + let guardExpr, tpenv = TcExpr cenv (MustEqual cenv.g.bool_ty) env tpenv guardExpr let innerExpr, tpenv = tcSequenceExprBody env genOuterTy tpenv innerComp let guardExprMark = guardExpr.Range @@ -1782,7 +1783,7 @@ let TcSequenceExpression (cenv: cenv) env tpenv comp overallTy m = | SynExpr.TryFinally (innerComp, unwindExpr, mTryToLast, spTry, spFinally) -> let innerExpr, tpenv = tcSequenceExprBody env genOuterTy tpenv innerComp - let (unwindExpr: Expr), tpenv = TcExpr cenv cenv.g.unit_ty env tpenv unwindExpr + let unwindExpr, tpenv = TcExpr cenv (MustEqual cenv.g.unit_ty) env tpenv unwindExpr // We attach the debug points to the lambda expressions so we can fetch it out again in LowerComputedListOrArraySeqExpr let mTry = @@ -1823,7 +1824,7 @@ let TcSequenceExpression (cenv: cenv) env tpenv comp overallTy m = Some(Expr.Sequential(stmt1, innerExpr2, NormalSeq, sp, m), tpenv) | SynExpr.IfThenElse (_, _, guardExpr, _, thenComp, _, elseCompOpt, spIfToThen, _isRecovery, mIfToThen, mIfToEndOfElseBranch) -> - let guardExpr', tpenv = TcExpr cenv cenv.g.bool_ty env tpenv guardExpr + let guardExpr', tpenv = TcExpr cenv (MustEqual cenv.g.bool_ty) env tpenv guardExpr let thenExpr, tpenv = tcSequenceExprBody env genOuterTy tpenv thenComp let elseComp = (match elseCompOpt with Some c -> c | None -> SynExpr.ImplicitZero mIfToThen) let elseExpr, tpenv = tcSequenceExprBody env genOuterTy tpenv elseComp @@ -1832,7 +1833,7 @@ let TcSequenceExpression (cenv: cenv) env tpenv comp overallTy m = // 'let x = expr in expr' | SynExpr.LetOrUse (_, false (* not a 'use' binding *), _, _, _) -> TcLinearExprs - (fun ty envinner tpenv e -> tcSequenceExprBody envinner ty tpenv e) + (fun overallTy envinner tpenv e -> tcSequenceExprBody envinner overallTy.Commit tpenv e) cenv env overallTy tpenv true @@ -1846,7 +1847,7 @@ let TcSequenceExpression (cenv: cenv) env tpenv comp overallTy m = let inputExprTy = NewInferenceType () let pat', _, vspecs, envinner, tpenv = TcMatchPattern cenv bindPatTy env tpenv (pat, None) UnifyTypes cenv env m inputExprTy bindPatTy - let (inputExpr: Expr), tpenv = TcExpr cenv inputExprTy env tpenv rhsExpr + let inputExpr, tpenv = TcExpr cenv (MustEqual inputExprTy) env tpenv rhsExpr let innerExpr, tpenv = tcSequenceExprBody envinner genOuterTy tpenv innerComp let mBind = match spBind with @@ -1897,7 +1898,7 @@ let TcSequenceExpression (cenv: cenv) env tpenv comp overallTy m = | _ -> None - and tcSequenceExprBody env genOuterTy tpenv comp = + and tcSequenceExprBody env (genOuterTy: TType) tpenv comp = let res, tpenv = tcSequenceExprBodyAsSequenceOrStatement env genOuterTy tpenv comp match res with | Choice1Of2 expr -> @@ -1927,11 +1928,11 @@ let TcSequenceExpression (cenv: cenv) env tpenv comp overallTy m = let stmt, tpenv = TcStmtThatCantBeCtorBody cenv env tpenv comp Choice2Of2 stmt, tpenv - let coreExpr, tpenv = tcSequenceExprBody env overallTy tpenv comp + let coreExpr, tpenv = tcSequenceExprBody env overallTy.Commit tpenv comp let delayedExpr = mkDelayedExpr coreExpr.Range coreExpr delayedExpr, tpenv -let TcSequenceExpressionEntry (cenv: cenv) env overallTy tpenv (isArrayOrList, isNotNakedRefCell, comp) m = +let TcSequenceExpressionEntry (cenv: cenv) env (overallTy: OverallTy) tpenv (isArrayOrList, isNotNakedRefCell, comp) m = let implicitYieldEnabled = cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitYield let validateObjectSequenceOrRecordExpression = not implicitYieldEnabled if not isArrayOrList then @@ -1977,16 +1978,18 @@ let TcArrayOrListSequenceExpression (cenv: cenv) env overallTy tpenv (isArray, c TcExprUndelayed cenv overallTy env tpenv replacementExpr | _ -> - let genCollElemTy = NewInferenceType () + let genCollElemTy = NewInferenceType () - let genCollTy = (if isArray then mkArrayType else mkListTy) cenv.g genCollElemTy - - UnifyTypes cenv env m overallTy genCollTy + let genCollTy = (if isArray then mkArrayType else mkListTy) cenv.g genCollElemTy + // Propagating type directed conversion, e.g. for + // let x : seq = [ yield 1; if true then yield 2 ] + TcPropagatingExprLeafThenConvert cenv overallTy genCollTy env (* canAdhoc *) m (fun () -> + let exprty = mkSeqTy cenv.g genCollElemTy // Check the comprehension - let expr, tpenv = TcExpr cenv exprty env tpenv comp + let expr, tpenv = TcExpr cenv (MustEqual exprty) env tpenv comp let expr = mkCoerceIfNeeded cenv.g exprty (tyOfExpr cenv.g expr) expr @@ -1999,7 +2002,7 @@ let TcArrayOrListSequenceExpression (cenv: cenv) env overallTy tpenv (isArray, c // comprehension. But don't do this in FSharp.Core.dll since 'seq' may not yet be defined. mkCallSeq cenv.g m genCollElemTy expr - let expr = mkCoerceExpr(expr, exprty, expr.Range, overallTy) + let expr = mkCoerceExpr(expr, exprty, expr.Range, overallTy.Commit) let expr = if isArray then @@ -2007,4 +2010,4 @@ let TcArrayOrListSequenceExpression (cenv: cenv) env overallTy tpenv (isArray, c else mkCallSeqToList cenv.g m genCollElemTy expr - expr, tpenv + expr, tpenv) diff --git a/src/fsharp/CheckComputationExpressions.fsi b/src/fsharp/CheckComputationExpressions.fsi index a6c8a46d136..c5644c756d6 100644 --- a/src/fsharp/CheckComputationExpressions.fsi +++ b/src/fsharp/CheckComputationExpressions.fsi @@ -3,13 +3,14 @@ module internal FSharp.Compiler.CheckComputationExpressions open FSharp.Compiler.CheckExpressions +open FSharp.Compiler.ConstraintSolver open FSharp.Compiler.Syntax open FSharp.Compiler.Text open FSharp.Compiler.TypedTree -val TcSequenceExpressionEntry: cenv:TcFileState -> env:TcEnv -> overallTy:TType -> tpenv:UnscopedTyparEnv -> isArrayOrList:bool * isNotNakedRefCell:bool ref * comp:SynExpr -> m:range -> Expr * UnscopedTyparEnv +val TcSequenceExpressionEntry: cenv:TcFileState -> env:TcEnv -> overallTy:OverallTy -> tpenv:UnscopedTyparEnv -> isArrayOrList:bool * isNotNakedRefCell:bool ref * comp:SynExpr -> m:range -> Expr * UnscopedTyparEnv -val TcArrayOrListSequenceExpression: cenv:TcFileState -> env:TcEnv -> overallTy:TType -> tpenv:UnscopedTyparEnv -> isArray:bool * comp:SynExpr -> m:range -> Expr * UnscopedTyparEnv +val TcArrayOrListSequenceExpression: cenv:TcFileState -> env:TcEnv -> overallTy:OverallTy -> tpenv:UnscopedTyparEnv -> isArray:bool * comp:SynExpr -> m:range -> Expr * UnscopedTyparEnv -val TcComputationExpression: cenv:TcFileState -> env:TcEnv -> overallTy:TType -> tpenv:UnscopedTyparEnv -> mWhole:range * interpExpr:Expr * builderTy:TType * comp:SynExpr -> Expr * UnscopedTyparEnv +val TcComputationExpression: cenv:TcFileState -> env:TcEnv -> overallTy:OverallTy -> tpenv:UnscopedTyparEnv -> mWhole:range * interpExpr:Expr * builderTy:TType * comp:SynExpr -> Expr * UnscopedTyparEnv diff --git a/src/fsharp/CheckDeclarations.fs b/src/fsharp/CheckDeclarations.fs index df6b0bf4c14..f8942a5beb2 100644 --- a/src/fsharp/CheckDeclarations.fs +++ b/src/fsharp/CheckDeclarations.fs @@ -1874,7 +1874,7 @@ module MutRecBindingChecking = let ty = generalizedTyconRef tcref let ad = envNonRec.AccessRights match TryFindIntrinsicMethInfo cenv.infoReader bind.Var.Range ad nm ty, - TryFindPropInfo cenv.infoReader bind.Var.Range ad nm ty with + TryFindIntrinsicPropInfo cenv.infoReader bind.Var.Range ad nm ty with | [], [] -> () | _ -> errorR (Error(FSComp.SR.tcMemberAndLocalClassBindingHaveSameName nm, bind.Var.Range)) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 12e40bbf11a..ffc9fc6f40c 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -406,11 +406,13 @@ type TcFileState = isInternalTestSpanStackReferring: bool // forward call - TcSequenceExpressionEntry: TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> bool * bool ref * SynExpr -> range -> Expr * UnscopedTyparEnv + TcSequenceExpressionEntry: TcFileState -> TcEnv -> OverallTy -> UnscopedTyparEnv -> bool * bool ref * SynExpr -> range -> Expr * UnscopedTyparEnv + // forward call - TcArrayOrListSequenceExpression: TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> bool * SynExpr -> range -> Expr * UnscopedTyparEnv + TcArrayOrListSequenceExpression: TcFileState -> TcEnv -> OverallTy -> UnscopedTyparEnv -> bool * SynExpr -> range -> Expr * UnscopedTyparEnv + // forward call - TcComputationExpression: TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> range * Expr * TType * SynExpr -> Expr * UnscopedTyparEnv + TcComputationExpression: TcFileState -> TcEnv -> OverallTy -> UnscopedTyparEnv -> range * Expr * TType * SynExpr -> Expr * UnscopedTyparEnv } /// Create a new compilation environment @@ -453,6 +455,52 @@ let CopyAndFixupTypars m rigid tpsorig = let UnifyTypes cenv (env: TcEnv) m actualTy expectedTy = AddCxTypeEqualsType env.eContextInfo env.DisplayEnv cenv.css m (tryNormalizeMeasureInType cenv.g actualTy) (tryNormalizeMeasureInType cenv.g expectedTy) +// If the overall type admits subsumption or type directed conversion, and the original unify would have failed, +// then allow subsumption or type directed conversion. +// +// Any call to UnifyOverallType MUST have a matching call to TcAdjustExprForTypeDirectedConversions +// to actually build the expression for any conversion applied. +let UnifyOverallType cenv (env: TcEnv) m overallTy actualTy = + match overallTy with + | MustConvertTo(isMethodArg, reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions -> + let actualTy = tryNormalizeMeasureInType cenv.g actualTy + let reqdTy = tryNormalizeMeasureInType cenv.g reqdTy + if AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css m reqdTy actualTy then + () + else + // try adhoc type-directed conversions + let reqdTy2, usesTDC, eqn = AdjustRequiredTypeForTypeDirectedConversions cenv.infoReader env.eAccessRights isMethodArg false reqdTy actualTy m + match eqn with + | Some (ty1, ty2, msg) -> + UnifyTypes cenv env m ty1 ty2 + msg env.DisplayEnv + | None -> () + match usesTDC with + | TypeDirectedConversionUsed.Yes warn -> warning(warn env.DisplayEnv) + | TypeDirectedConversionUsed.No -> () + if AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m reqdTy2 actualTy then + let reqdTyText, actualTyText, _cxs = NicePrint.minimalStringsOfTwoTypes env.DisplayEnv reqdTy actualTy + warning (Error(FSComp.SR.tcSubsumptionImplicitConversionUsed(actualTyText, reqdTyText), m)) + else + // report the error + UnifyTypes cenv env m reqdTy actualTy + | _ -> + UnifyTypes cenv env m overallTy.Commit actualTy + +let UnifyOverallTypeAndRecover cenv env m overallTy actualTy = + try + UnifyOverallType cenv env m overallTy actualTy + with e -> + errorRecovery e m + +// Calls UnifyTypes, but upon error only does the minimal error recovery +// so that IntelliSense information can continue to be collected. +let UnifyTypesAndRecover cenv env m expectedTy actualTy = + try + UnifyTypes cenv env m expectedTy actualTy + with e -> + errorRecovery e m + /// Make an environment suitable for a module or namespace. Does not create a new accumulator but uses one we already have/ let MakeInnerEnvWithAcc addOpenToNameEnv env nm mtypeAcc modKind = let path = env.ePath @ [nm] @@ -515,7 +563,6 @@ let LocateEnv ccu env enclosingNamespacePath = let env = { env with eNameResEnv = { env.NameEnv with eDisplayEnv = env.DisplayEnv.AddOpenPath (pathOfLid env.ePath) } } env - //------------------------------------------------------------------------- // Helpers for unification //------------------------------------------------------------------------- @@ -745,7 +792,7 @@ let rec TcSynRationalConst c = | SynRationalConst.Rational(p, q, _) -> DivRational (intToRational p) (intToRational q) /// Typecheck constant terms in expressions and patterns -let TcConst cenv ty m env c = +let TcConst cenv (overallTy: TType) m env c = let rec tcMeasure ms = match ms with | SynMeasure.One -> Measure.One @@ -767,7 +814,7 @@ let TcConst cenv ty m env c = | SynMeasure.Anon _ -> error(Error(FSComp.SR.tcUnexpectedMeasureAnon(), m)) | SynMeasure.Var(_, m) -> error(Error(FSComp.SR.tcNonZeroConstantCannotHaveGenericUnit(), m)) - let unif expected = UnifyTypes cenv env m ty expected + let unif expected = UnifyTypes cenv env m overallTy expected let unifyMeasureArg iszero tcr c = let measureTy = @@ -2907,7 +2954,7 @@ let TryFindIntrinsicOrExtensionMethInfo collectionSettings (cenv: cenv) (env: Tc AllMethInfosOfTypeInScope collectionSettings cenv.infoReader env.NameEnv (Some nm) ad IgnoreOverrides m ty let TryFindFSharpSignatureInstanceGetterProperty (cenv: cenv) (env: TcEnv) m nm ty (sigTys: TType list) = - TryFindPropInfo cenv.infoReader m env.AccessRights nm ty + TryFindIntrinsicPropInfo cenv.infoReader m env.AccessRights nm ty |> List.tryFind (fun propInfo -> not propInfo.IsStatic && propInfo.HasGetter && ( @@ -4440,7 +4487,7 @@ and TcStaticConstantParameter cenv (env: TcEnv) tpenv kind (StripParenTypes v) i | SynType.StaticConstantExpr(e, _ ) -> // If an error occurs, don't try to recover, since the constant expression will be nothing like what we need - let te, tpenv' = TcExprNoRecover cenv kind env tpenv e + let te, tpenv' = TcExprNoRecover cenv (MustEqual kind) env tpenv e // Evaluate the constant expression using static attribute argument rules let te = EvalLiteralExprOrAttribArg g te @@ -5012,7 +5059,7 @@ and TcPat warnOnUpper cenv env topValInfo vFlags (tpenv, names, takenNames) ty p let activePatType = apinfo.OverallType cenv.g m ty activePatResTys isStructRetTy let delayed = activePatArgsAsSynExprs |> List.map (fun arg -> DelayedApp(ExprAtomicFlag.NonAtomic, arg, unionRanges (rangeOfLid longId) arg.Range)) - let activePatExpr, tpenv = PropagateThenTcDelayed cenv activePatType env tpenv m vexp vexpty ExprAtomicFlag.NonAtomic delayed + let activePatExpr, tpenv = PropagateThenTcDelayed cenv (MustEqual activePatType) env tpenv m vexp vexpty ExprAtomicFlag.NonAtomic delayed if idx >= activePatResTys.Length then error(Error(FSComp.SR.tcInvalidIndexIntoActivePatternArray(), m)) let argty = List.item idx activePatResTys @@ -5275,31 +5322,27 @@ and RecordNameAndTypeResolutions_IdeallyWithoutHavingOtherEffects_Delayed cenv e | _ -> () dummyCheckedDelayed delayed -// Calls UnifyTypes, but upon error only does the minimal error recovery -// so that IntelliSense information can continue to be collected. -and UnifyTypesAndRecover cenv env m expectedTy actualTy = - try - UnifyTypes cenv env m expectedTy actualTy - with e -> - errorRecovery e m - and TcExprOfUnknownType cenv env tpenv expr = let exprty = NewInferenceType () - let expr', tpenv = TcExpr cenv exprty env tpenv expr + let expr', tpenv = TcExpr cenv (MustEqual exprty) env tpenv expr expr', exprty, tpenv -and TcExprFlex cenv flex compat ty (env: TcEnv) tpenv (e: SynExpr) = +and TcExprFlex cenv flex compat (desiredTy: TType) (env: TcEnv) tpenv (synExpr: SynExpr) = + // This is the old way of introducing flexibility via subtype constraints, still active + // for compat reasons. if flex then let argty = NewInferenceType () if compat then (destTyparTy cenv.g argty).SetIsCompatFlex(true) - AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css e.Range NoTrace ty argty - let e', tpenv = TcExpr cenv argty env tpenv e - let e' = mkCoerceIfNeeded cenv.g ty argty e' - e', tpenv + AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css synExpr.Range NoTrace desiredTy argty + let expr2, tpenv = TcExprFlex2 cenv argty env false tpenv synExpr + let expr3 = mkCoerceIfNeeded cenv.g desiredTy argty expr2 + expr3, tpenv else - TcExpr cenv ty env tpenv e + TcExprFlex2 cenv desiredTy env false tpenv synExpr +and TcExprFlex2 cenv desiredTy env isMethodArg tpenv synExpr = + TcExpr cenv (MustConvertTo (isMethodArg, desiredTy)) env tpenv synExpr and TcExpr cenv ty (env: TcEnv) tpenv (expr: SynExpr) = // Start an error recovery handler @@ -5312,10 +5355,10 @@ and TcExpr cenv ty (env: TcEnv) tpenv (expr: SynExpr) = // Error recovery - return some rubbish expression, but replace/annotate // the type of the current expression with a type variable that indicates an error errorRecovery e m - solveTypAsError cenv env.DisplayEnv m ty - mkThrow m ty (mkOne cenv.g m), tpenv + solveTypAsError cenv env.DisplayEnv m ty.Commit + mkThrow m ty.Commit (mkOne cenv.g m), tpenv -and TcExprNoRecover cenv ty (env: TcEnv) tpenv (expr: SynExpr) = +and TcExprNoRecover cenv (ty: OverallTy) (env: TcEnv) tpenv (expr: SynExpr) = // Count our way through the expression shape that makes up an object constructor // See notes at definition of "ctor" re. object model constructors. @@ -5325,7 +5368,6 @@ and TcExprNoRecover cenv ty (env: TcEnv) tpenv (expr: SynExpr) = TcExprThen cenv ty env tpenv expr [] - // This recursive entry is only used from one callsite (DiscardAfterMissingQualificationAfterDot) // and has been added relatively late in F# 4.0 to preserve the structure of previous code. It pushes a 'delayed' parameter // through TcExprOfUnknownType, TcExpr and TcExprNoRecover @@ -5333,7 +5375,7 @@ and TcExprOfUnknownTypeThen cenv env tpenv expr delayed = let exprty = NewInferenceType () let expr', tpenv = try - TcExprThen cenv exprty env tpenv expr delayed + TcExprThen cenv (MustEqual exprty) env tpenv expr delayed with e -> let m = expr.Range errorRecovery e m @@ -5382,7 +5424,7 @@ and TryTcStmt cenv env tpenv synExpr = /// During checking of expressions of the form (x(y)).z(w1, w2) /// keep a stack of things on the right. This lets us recognize /// method applications and other item-based syntax. -and TcExprThen cenv overallTy env tpenv synExpr delayed = +and TcExprThen cenv (overallTy: OverallTy) env tpenv synExpr delayed = match synExpr with | LongOrSingleIdent (isOpt, longId, altNameRefCellOpt, mLongId) -> @@ -5425,7 +5467,7 @@ and TcExprThen cenv overallTy env tpenv synExpr delayed = let expr, exprty, tpenv = TcExprUndelayedNoType cenv env tpenv synExpr PropagateThenTcDelayed cenv overallTy env tpenv synExpr.Range (MakeApplicableExprNoFlex cenv expr) exprty ExprAtomicFlag.NonAtomic delayed -and TcExprs cenv env m tpenv flexes argTys args = +and TcExprsWithFlexes cenv env m tpenv flexes argTys args = if List.length args <> List.length argTys then error(Error(FSComp.SR.tcExpressionCountMisMatch((List.length argTys), (List.length args)), m)) (tpenv, List.zip3 flexes argTys args) ||> List.mapFold (fun tpenv (flex, ty, e) -> TcExprFlex cenv flex false ty env tpenv e) @@ -5443,16 +5485,101 @@ and CheckSuperInit cenv objTy m = and TcExprUndelayedNoType cenv env tpenv synExpr: Expr * TType * _ = let overallTy = NewInferenceType () - let expr, tpenv = TcExprUndelayed cenv overallTy env tpenv synExpr + let expr, tpenv = TcExprUndelayed cenv (MustEqual overallTy) env tpenv synExpr expr, overallTy, tpenv -and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = +/// Process a leaf construct where the actual type (or an approximation of it such as 'list<_>' +/// or 'array<_>') is already sufficiently pre-known, and the information in the overall type +/// can be eagerly propagated into the actual type (UnifyOverallType), including pre-calculating +/// any type-directed conversion. This must mean that types extracted when processing the expression are not +/// considered in determining any type-directed conversion. +/// +/// Used for: +/// - Array or List expressions (both computed and fixed-size), to propagate from the overall type into the array/list type +/// e.g. to infer element types, which may be relevant to processing each individual expression and the 'yield' +/// returns. +/// +/// - 'new ABC<_>(args)' expressions, to propagate from the overall type into the 'ABC<_>' type, e.g. to infer type parameters, +/// which may be relevant to checking the arguments. +/// +/// - object expressions '{ new ABC<_>(args) with ... }', to propagate from the overall type into the +/// object type, e.g. to infer type parameters, which may be relevant to checking the arguments and +/// methods of the object expression. +/// +/// - string literal expressions (though the propagation is not essential in this case) +/// +and TcPropagatingExprLeafThenConvert cenv overallTy actualTy (env: TcEnv) (* canAdhoc *) m (f: unit -> Expr * UnscopedTyparEnv) = + match overallTy with + | MustConvertTo _ when cenv.g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions -> + assert (cenv.g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions) + //if not canAdhoc then + // AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace reqdTy actualTy + // Compute the conversion _before_ processing the construct. We know enough to process this conversion eagerly. + UnifyOverallType cenv env m overallTy actualTy + // Process the construct + let expr, tpenv = f () + // Build the conversion + let expr2 = TcAdjustExprForTypeDirectedConversions cenv overallTy actualTy env (* canAdhoc *) m expr + expr2, tpenv + | _ -> + UnifyTypes cenv env m overallTy.Commit actualTy + f () + +/// Process a leaf construct, for cases where we propogate the overall type eagerly in +/// some cases. Then apply additional type-directed conversions. +/// +/// However in some cases favour propagating characteristics of the overall type. +/// +/// 'isPropagating' indicates if propagation occurs +/// 'processExpr' does the actual processing of the construct. +/// +/// Used for +/// - tuple (exception is if overallTy is a tuple type, used to propagate structness from known type) +/// - anon record (exception is if overallTy is an anon record type, similarly) +/// - record (exception is (fun ty -> requiresCtor || haveCtor || isRecdTy cenv.g ty), similarly) +and TcPossiblyPropogatingExprLeafThenConvert isPropagating cenv (overallTy: OverallTy) (env: TcEnv) m processExpr = + match overallTy with + | MustConvertTo(_, reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && not (isPropagating reqdTy) -> + TcNonPropagatingExprLeafThenConvert cenv overallTy env m (fun () -> + let exprTy = NewInferenceType() + // Here 'processExpr' will do the unification with exprTy. + let expr, tpenv = processExpr exprTy + expr, exprTy, tpenv) + | _ -> + // Here 'processExpr' will do the unification with the overall type. + processExpr overallTy.Commit + +/// Process a leaf construct where the processing of the construct is initially independent +/// of the overall type. Determine and apply additional type-directed conversions after the processing +/// is complete, as the inferred type of the expression may enable a type-directed conversion. +/// +/// Used for: +/// - trait call +/// - LibraryOnlyUnionCaseFieldGet +/// - constants +and TcNonPropagatingExprLeafThenConvert cenv (overallTy: OverallTy) (env: TcEnv) m processExpr = + // Process the construct + let expr, exprTy, tpenv = processExpr () + // Now compute the conversion, based on the post-processing type + UnifyOverallType cenv env m overallTy exprTy + let expr2 = TcAdjustExprForTypeDirectedConversions cenv overallTy exprTy env (* true *) m expr + expr2, tpenv + +and TcAdjustExprForTypeDirectedConversions cenv (overallTy: OverallTy) actualTy (env: TcEnv) (* canAdhoc *) m expr = + match overallTy with + | MustConvertTo (_, reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions -> + let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g + AdjustExprForTypeDirectedConversions tcVal cenv.g cenv.amap cenv.infoReader env.AccessRights reqdTy actualTy m expr + | _ -> + expr + +and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = match synExpr with | SynExpr.Paren (expr2, _, _, mWholeExprIncludingParentheses) -> // We invoke CallExprHasTypeSink for every construct which is atomic in the syntax, i.e. where a '.' immediately following the // construct is a dot-lookup for the result of the construct. - CallExprHasTypeSink cenv.tcSink (mWholeExprIncludingParentheses, env.NameEnv, overallTy, env.AccessRights) + CallExprHasTypeSink cenv.tcSink (mWholeExprIncludingParentheses, env.NameEnv, overallTy.Commit, env.AccessRights) let env = ShrinkContext env mWholeExprIncludingParentheses expr2.Range TcExpr cenv overallTy env tpenv expr2 @@ -5460,18 +5587,18 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = | SynExpr.TypeApp _ | SynExpr.Ident _ | SynExpr.LongIdent _ | SynExpr.App _ | SynExpr.DotGet _ -> error(Error(FSComp.SR.tcExprUndelayed(), synExpr.Range)) | SynExpr.Const (SynConst.String (s, _, m), _) -> - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights) + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) TcConstStringExpr cenv overallTy env m tpenv s | SynExpr.InterpolatedString (parts, _, m) -> checkLanguageFeatureError cenv.g.langVersion LanguageFeature.StringInterpolation m - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights) + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) TcInterpolatedStringExpr cenv overallTy env m tpenv parts | SynExpr.Const (synConst, m) -> - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights) + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) TcConstExpr cenv overallTy env m tpenv synConst | SynExpr.Lambda _ -> @@ -5497,10 +5624,10 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = | SynExpr.MatchLambda (isExnMatch, mArg, clauses, spMatch, m) -> - let domainTy, resultTy = UnifyFunctionType None cenv env.DisplayEnv m overallTy + let domainTy, resultTy = UnifyFunctionType None cenv env.DisplayEnv m overallTy.Commit let idv1, idve1 = mkCompGenLocal mArg (cenv.synArgNameGenerator.New()) domainTy let envinner = ExitFamilyRegion env - let idv2, matchExpr, tpenv = TcAndPatternCompileMatchClauses m mArg (if isExnMatch then Throw else ThrowIncompleteMatchException) cenv None domainTy resultTy envinner tpenv clauses + let idv2, matchExpr, tpenv = TcAndPatternCompileMatchClauses m mArg (if isExnMatch then Throw else ThrowIncompleteMatchException) cenv None domainTy (MustConvertTo (false, resultTy)) envinner tpenv clauses let overallExpr = mkMultiLambda m [idv1] ((mkLet spMatch m idv2 idve1 matchExpr), resultTy) overallExpr, tpenv @@ -5513,14 +5640,15 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = // e: ty | SynExpr.Typed (synBodyExpr, synType, m) -> let tgtTy, tpenv = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synType - UnifyTypes cenv env m overallTy tgtTy - let expr, tpenv = TcExpr cenv overallTy env tpenv synBodyExpr - expr, tpenv + UnifyOverallType cenv env m overallTy tgtTy + let bodyExpr, tpenv = TcExpr cenv (MustConvertTo (false, tgtTy)) env tpenv synBodyExpr + let bodyExpr2 = TcAdjustExprForTypeDirectedConversions cenv overallTy tgtTy env (* true *) m bodyExpr + bodyExpr2, tpenv // e :? ty | SynExpr.TypeTest (synInnerExpr, tgtTy, m) -> let innerExpr, srcTy, tpenv = TcExprOfUnknownType cenv env tpenv synInnerExpr - UnifyTypes cenv env m overallTy cenv.g.bool_ty + UnifyTypes cenv env m overallTy.Commit cenv.g.bool_ty let tgtTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv tgtTy TcRuntimeTypeTest (*isCast*)false (*isOperator*)true cenv env.DisplayEnv m tgtTy srcTy let expr = mkCallTypeTest cenv.g m tgtTy innerExpr @@ -5538,10 +5666,10 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = match synExpr with | SynExpr.Upcast (_, tgtTy, m) -> let tgtTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv tgtTy - UnifyTypes cenv env m tgtTy overallTy + UnifyTypes cenv env m tgtTy overallTy.Commit tgtTy, tpenv | SynExpr.InferredUpcast _ -> - overallTy, tpenv + overallTy.Commit, tpenv | _ -> failwith "upcast" TcStaticUpcast cenv env.DisplayEnv m tgtTy srcTy let expr = mkCoerceExpr(innerExpr, tgtTy, m, srcTy) @@ -5553,9 +5681,9 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = match synExpr with | SynExpr.Downcast (_, tgtTy, m) -> let tgtTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv tgtTy - UnifyTypes cenv env m tgtTy overallTy + UnifyTypes cenv env m tgtTy overallTy.Commit tgtTy, tpenv, true - | SynExpr.InferredDowncast _ -> overallTy, tpenv, false + | SynExpr.InferredDowncast _ -> overallTy.Commit, tpenv, false | _ -> failwith "downcast" TcRuntimeTypeTest (*isCast*)true isOperator cenv env.DisplayEnv m tgtTy srcTy @@ -5565,32 +5693,42 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = expr, tpenv | SynExpr.Null m -> - AddCxTypeMustSupportNull env.DisplayEnv cenv.css m NoTrace overallTy - mkNull m overallTy, tpenv + AddCxTypeMustSupportNull env.DisplayEnv cenv.css m NoTrace overallTy.Commit + mkNull m overallTy.Commit, tpenv | SynExpr.Lazy (synInnerExpr, m) -> let innerTy = NewInferenceType () - UnifyTypes cenv env m overallTy (mkLazyTy cenv.g innerTy) - let innerExpr, tpenv = TcExpr cenv innerTy env tpenv synInnerExpr + UnifyTypes cenv env m overallTy.Commit (mkLazyTy cenv.g innerTy) + let innerExpr, tpenv = TcExpr cenv (MustEqual innerTy) env tpenv synInnerExpr let expr = mkLazyDelayed cenv.g m innerTy (mkUnitDelayLambda cenv.g m innerExpr) expr, tpenv | SynExpr.Tuple (isExplicitStruct, args, _, m) -> - let tupInfo, argTys = UnifyTupleTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv m overallTy isExplicitStruct args - // No subsumption at tuple construction - let flexes = argTys |> List.map (fun _ -> false) - let args', tpenv = TcExprs cenv env m tpenv flexes argTys args - let expr = mkAnyTupled cenv.g m tupInfo args' argTys - expr, tpenv + TcPossiblyPropogatingExprLeafThenConvert (isAnyTupleTy cenv.g) cenv overallTy env m (fun overallTy -> + let tupInfo, argTys = UnifyTupleTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv m overallTy isExplicitStruct args + + let flexes = argTys |> List.map (fun _ -> false) + let args', tpenv = TcExprsWithFlexes cenv env m tpenv flexes argTys args + let expr = mkAnyTupled cenv.g m tupInfo args' argTys + expr, tpenv + ) | SynExpr.AnonRecd (isStruct, optOrigExpr, unsortedFieldExprs, mWholeExpr) -> - TcAnonRecdExpr cenv overallTy env tpenv (isStruct, optOrigExpr, unsortedFieldExprs, mWholeExpr) + TcPossiblyPropogatingExprLeafThenConvert (isAnonRecdTy cenv.g) cenv overallTy env mWholeExpr (fun overallTy -> + TcAnonRecdExpr cenv overallTy env tpenv (isStruct, optOrigExpr, unsortedFieldExprs, mWholeExpr) + ) | SynExpr.ArrayOrList (isArray, args, m) -> - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights) + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) + let argty = NewInferenceType () + let actualTy = if isArray then mkArrayType cenv.g argty else mkListTy cenv.g argty - let argty = NewInferenceType () - UnifyTypes cenv env m overallTy (if isArray then mkArrayType cenv.g argty else mkListTy cenv.g argty) + // Propagating type directed conversion, e.g. for + // let x : seq = [ 1; 2 ] + // Consider also the case where there is no relation but an op_Implicit is enabled from List<_> to C + // let x : C = [ B(); B() ] + + TcPropagatingExprLeafThenConvert cenv overallTy actualTy env (* canAdhoc *) m (fun () -> // Always allow subsumption if a nominal type is known prior to type checking any arguments let flex = not (isTyparTy cenv.g argty) @@ -5608,30 +5746,65 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = if isArray then Expr.Op (TOp.Array, [argty], args', m) else List.foldBack (mkCons cenv.g argty) args' (mkNil cenv.g m argty) expr, tpenv + ) | SynExpr.New (superInit, synObjTy, arg, mNewExpr) -> - let objTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.Use env tpenv synObjTy - UnifyTypes cenv env mNewExpr overallTy objTy + let objTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.Use env tpenv synObjTy + + TcPropagatingExprLeafThenConvert cenv overallTy objTy env (* true *) mNewExpr (fun () -> TcNewExpr cenv env tpenv objTy (Some synObjTy.Range) superInit arg mNewExpr + ) - | SynExpr.ObjExpr (objTy, argopt, binds, extraImpls, mNewExpr, m) -> - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.eAccessRights) - TcObjectExpr cenv overallTy env tpenv (objTy, argopt, binds, extraImpls, mNewExpr, m) + | SynExpr.ObjExpr (synObjTy, argopt, binds, extraImpls, mNewExpr, m) -> + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.eAccessRights) + + // Note, allowing canAdhoc = true would disable subtype-based propagation from overallTy into checking of structure + // + // For example + // let x : A seq = { new Collection<_> with ... the element type should be known in here! } + // + // So op_Implicit is effectively disabled for direct uses of object expressions + //let canAdhoc = false + + let mObjTy = synObjTy.Range + + let objTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synObjTy + + // Work out the type of any interfaces to implement + let extraImpls, tpenv = + (tpenv, extraImpls) ||> List.mapFold (fun tpenv (SynInterfaceImpl(synIntfTy, overrides, m)) -> + let intfTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synIntfTy + if not (isInterfaceTy cenv.g intfTy) then + error(Error(FSComp.SR.tcExpectedInterfaceType(), m)) + if isErasedType cenv.g intfTy then + errorR(Error(FSComp.SR.tcCannotInheritFromErasedType(), m)) + (m, intfTy, overrides), tpenv) + + let realObjTy = if isObjTy cenv.g objTy && not (isNil extraImpls) then (p23 (List.head extraImpls)) else objTy + + TcPropagatingExprLeafThenConvert cenv overallTy realObjTy env (* canAdhoc *) m (fun () -> + TcObjectExpr cenv env tpenv (objTy, realObjTy, argopt, binds, extraImpls, mObjTy, mNewExpr, m) + ) | SynExpr.Record (inherits, optOrigExpr, flds, mWholeExpr) -> - CallExprHasTypeSink cenv.tcSink (mWholeExpr, env.NameEnv, overallTy, env.AccessRights) + + CallExprHasTypeSink cenv.tcSink (mWholeExpr, env.NameEnv, overallTy.Commit, env.AccessRights) + let requiresCtor = (GetCtorShapeCounter env = 1) // Get special expression forms for constructors + let haveCtor = Option.isSome inherits + TcPossiblyPropogatingExprLeafThenConvert (fun ty -> requiresCtor || haveCtor || isRecdTy cenv.g ty) cenv overallTy env mWholeExpr (fun overallTy -> TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr) + ) | SynExpr.While (spWhile, synGuardExpr, synBodyExpr, m) -> - UnifyTypes cenv env m overallTy cenv.g.unit_ty - let guardExpr, tpenv = TcExpr cenv cenv.g.bool_ty env tpenv synGuardExpr + UnifyTypes cenv env m overallTy.Commit cenv.g.unit_ty + let guardExpr, tpenv = TcExpr cenv (MustEqual cenv.g.bool_ty) env tpenv synGuardExpr let bodyExpr, tpenv = TcStmt cenv env tpenv synBodyExpr mkWhile cenv.g (spWhile, NoSpecialWhileLoopMarker, guardExpr, bodyExpr, m), tpenv | SynExpr.For (spBind, id, start, dir, finish, body, m) -> - UnifyTypes cenv env m overallTy cenv.g.unit_ty - let startExpr, tpenv = TcExpr cenv cenv.g.int_ty env tpenv start - let finishExpr, tpenv = TcExpr cenv cenv.g.int_ty env tpenv finish + UnifyTypes cenv env m overallTy.Commit cenv.g.unit_ty + let startExpr, tpenv = TcExpr cenv (MustEqual cenv.g.int_ty) env tpenv start + let finishExpr, tpenv = TcExpr cenv (MustEqual cenv.g.int_ty) env tpenv finish let idv, _ = mkLocal id.idRange id.idText cenv.g.int_ty let envinner = AddLocalVal cenv.g cenv.tcSink m idv env @@ -5652,7 +5825,7 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = cenv.TcSequenceExpressionEntry cenv env overallTy tpenv (isArrayOrList, isNotNakedRefCell, comp) m | SynExpr.ArrayOrListOfSeqExpr (isArray, comp, m) -> - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.eAccessRights) + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.eAccessRights) cenv.TcArrayOrListSequenceExpression cenv env overallTy tpenv (isArray, comp) m | SynExpr.LetOrUse _ -> @@ -5661,37 +5834,40 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = | SynExpr.TryWith (synBodyExpr, _mTryToWith, synWithClauses, mWithToLast, mTryToLast, spTry, spWith) -> let bodyExpr, tpenv = TcExpr cenv overallTy env tpenv synBodyExpr // Compile the pattern twice, once as a List.filter with all succeeding targets returning "1", and once as a proper catch block. - let filterClauses = synWithClauses |> List.map (function SynMatchClause(pat, optWhenExpr, arrow, _, m, _) -> SynMatchClause(pat, optWhenExpr, arrow, (SynExpr.Const (SynConst.Int32 1, m)), m, DebugPointForTarget.No)) - let checkedFilterClauses, tpenv = TcMatchClauses cenv cenv.g.exn_ty cenv.g.int_ty env tpenv filterClauses + let filterClauses = + synWithClauses |> List.map (fun clause -> + let (SynMatchClause(pat, optWhenExpr, arrow, _, m, _)) = clause + let oneExpr = SynExpr.Const (SynConst.Int32 1, m) + SynMatchClause(pat, optWhenExpr, arrow, oneExpr, m, DebugPointForTarget.No)) + let checkedFilterClauses, tpenv = TcMatchClauses cenv cenv.g.exn_ty (MustEqual cenv.g.int_ty) env tpenv filterClauses let checkedHandlerClauses, tpenv = TcMatchClauses cenv cenv.g.exn_ty overallTy env tpenv synWithClauses let v1, filterExpr = CompilePatternForMatchClauses cenv env mWithToLast mWithToLast true FailFilter None cenv.g.exn_ty cenv.g.int_ty checkedFilterClauses - let v2, handlerExpr = CompilePatternForMatchClauses cenv env mWithToLast mWithToLast true Rethrow None cenv.g.exn_ty overallTy checkedHandlerClauses - mkTryWith cenv.g (bodyExpr, v1, filterExpr, v2, handlerExpr, mTryToLast, overallTy, spTry, spWith), tpenv + let v2, handlerExpr = CompilePatternForMatchClauses cenv env mWithToLast mWithToLast true Rethrow None cenv.g.exn_ty overallTy.Commit checkedHandlerClauses + mkTryWith cenv.g (bodyExpr, v1, filterExpr, v2, handlerExpr, mTryToLast, overallTy.Commit, spTry, spWith), tpenv | SynExpr.TryFinally (synBodyExpr, synFinallyExpr, mTryToLast, spTry, spFinally) -> let bodyExpr, tpenv = TcExpr cenv overallTy env tpenv synBodyExpr let finallyExpr, tpenv = TcStmt cenv env tpenv synFinallyExpr - mkTryFinally cenv.g (bodyExpr, finallyExpr, mTryToLast, overallTy, spTry, spFinally), tpenv + mkTryFinally cenv.g (bodyExpr, finallyExpr, mTryToLast, overallTy.Commit, spTry, spFinally), tpenv | SynExpr.JoinIn (e1, mInToken, e2, mAll) -> errorR(Error(FSComp.SR.parsUnfinishedExpression("in"), mInToken)) let _, _, tpenv = suppressErrorReporting (fun () -> TcExprOfUnknownType cenv env tpenv e1) let _, _, tpenv = suppressErrorReporting (fun () -> TcExprOfUnknownType cenv env tpenv e2) - mkDefault(mAll, overallTy), tpenv + mkDefault(mAll, overallTy.Commit), tpenv | SynExpr.ArbitraryAfterError (_debugStr, m) -> //solveTypAsError cenv env.DisplayEnv m overallTy - mkDefault(m, overallTy), tpenv + mkDefault(m, overallTy.Commit), tpenv - // expr. (already reported as an error) | SynExpr.DiscardAfterMissingQualificationAfterDot (e1, m) -> let _, _, tpenv = suppressErrorReporting (fun () -> TcExprOfUnknownTypeThen cenv env tpenv e1 [DelayedDot]) - mkDefault(m, overallTy), tpenv + mkDefault(m, overallTy.Commit), tpenv | SynExpr.FromParseError (e1, m) -> //solveTypAsError cenv env.DisplayEnv m overallTy let _, tpenv = suppressErrorReporting (fun () -> TcExpr cenv overallTy env tpenv e1) - mkDefault(m, overallTy), tpenv + mkDefault(m, overallTy.Commit), tpenv | SynExpr.Sequential (sp, dir, synExpr1, synExpr2, m) -> if dir then @@ -5718,7 +5894,7 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = TcExpr cenv overallTy env tpenv otherExpr | SynExpr.Do (synInnerExpr, m) -> - UnifyTypes cenv env m overallTy cenv.g.unit_ty + UnifyTypes cenv env m overallTy.Commit cenv.g.unit_ty TcStmtThatCantBeCtorBody cenv env tpenv synInnerExpr | SynExpr.IfThenElse _ -> @@ -5773,6 +5949,7 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = TcLongIdentThen cenv overallTy env tpenv lidwd [ DelayedApp(ExprAtomicFlag.Atomic, e1, mStmt); MakeDelayedSet(e2, mStmt) ] | SynExpr.TraitCall (tps, memSpfn, arg, m) -> + TcNonPropagatingExprLeafThenConvert cenv overallTy env m (fun () -> let synTypes = tps |> List.map (fun tp -> SynType.Var(tp, m)) let traitInfo, tpenv = TcPseudoMemberSpec cenv NewTyparsOK env synTypes tpenv memSpfn m if BakedInTraitConstraintNames.Contains traitInfo.MemberName then @@ -5784,21 +5961,22 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = if not (isNil namedCallerArgs) then errorR(Error(FSComp.SR.tcNamedArgumentsCannotBeUsedInMemberTraits(), m)) // Subsumption at trait calls if arguments have nominal type prior to unification of any arguments or return type let flexes = argTys |> List.map (isTyparTy cenv.g >> not) - let args', tpenv = TcExprs cenv env m tpenv flexes argTys args + let args', tpenv = TcExprsWithFlexes cenv env m tpenv flexes argTys args AddCxMethodConstraint env.DisplayEnv cenv.css m NoTrace traitInfo - UnifyTypes cenv env m overallTy returnTy - Expr.Op (TOp.TraitCall traitInfo, [], args', m), tpenv + Expr.Op (TOp.TraitCall traitInfo, [], args', m), returnTy, tpenv + ) | SynExpr.LibraryOnlyUnionCaseFieldGet (e1, c, n, m) -> + TcNonPropagatingExprLeafThenConvert cenv overallTy env m (fun () -> let e1', ty1, tpenv = TcExprOfUnknownType cenv env tpenv e1 let mkf, ty2 = TcUnionCaseOrExnField cenv env ty1 m c n ((fun (a, b) n -> mkUnionCaseFieldGetUnproven cenv.g (e1', a, b, n, m)), (fun a n -> mkExnCaseFieldGet(e1', a, n, m))) - UnifyTypes cenv env m overallTy ty2 - mkf n, tpenv + mkf n, ty2, tpenv + ) | SynExpr.LibraryOnlyUnionCaseFieldSet (e1, c, n, e2, m) -> - UnifyTypes cenv env m overallTy cenv.g.unit_ty + UnifyTypes cenv env m overallTy.Commit cenv.g.unit_ty let e1', ty1, tpenv = TcExprOfUnknownType cenv env tpenv e1 let mkf, ty2 = TcUnionCaseOrExnField cenv env ty1 m c n ((fun (a, b) n e2' -> @@ -5807,7 +5985,7 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = (fun a n e2' -> if not (isExnFieldMutable a n) then errorR(Error(FSComp.SR.tcFieldIsNotMutable(), m)) mkExnCaseFieldSet(e1', a, n, e2', m))) - let e2', tpenv = TcExpr cenv ty2 env tpenv e2 + let e2', tpenv = TcExpr cenv (MustEqual ty2) env tpenv e2 mkf n e2', tpenv | SynExpr.LibraryOnlyILAssembly (s, tyargs, args, rtys, m) -> @@ -5816,18 +5994,18 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = let tyargs', tpenv = TcTypes cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv tyargs // No subsumption at uses of IL assembly code let flexes = argTys |> List.map (fun _ -> false) - let args', tpenv = TcExprs cenv env m tpenv flexes argTys args + let args', tpenv = TcExprsWithFlexes cenv env m tpenv flexes argTys args let rtys', tpenv = TcTypes cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv rtys let returnTy = match rtys' with | [] -> cenv.g.unit_ty | [ returnTy ] -> returnTy | _ -> error(InternalError("Only zero or one pushed items are permitted in IL assembly code", m)) - UnifyTypes cenv env m overallTy returnTy + UnifyTypes cenv env m overallTy.Commit returnTy mkAsmExpr (Array.toList s, tyargs', args', rtys', m), tpenv | SynExpr.Quote (oper, raw, ast, isFromQueryExpression, m) -> - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights) + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) TcQuotationExpr cenv overallTy env tpenv (oper, raw, ast, isFromQueryExpression, m) | SynExpr.YieldOrReturn ((isTrueYield, _), _, m) @@ -5854,7 +6032,7 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = and TcIteratedLambdas cenv isFirst (env: TcEnv) overallTy takenNames tpenv e = match e with | SynExpr.Lambda (isMember, isSubsequent, spats, _, bodyExpr, _, m) when isMember || isFirst || isSubsequent -> - let domainTy, resultTy = UnifyFunctionType None cenv env.DisplayEnv m overallTy + let domainTy, resultTy = UnifyFunctionType None cenv env.DisplayEnv m overallTy.Commit let vs, (tpenv, names, takenNames) = TcSimplePats cenv isMember CheckCxs domainTy env (tpenv, Map.empty, takenNames) spats let envinner, _, vspecMap = MakeAndPublishSimpleValsForMergedScope cenv env m names let byrefs = vspecMap |> Map.map (fun _ v -> isByrefTy cenv.g v.Type, v) @@ -5873,7 +6051,7 @@ and TcIteratedLambdas cenv isFirst (env: TcEnv) overallTy takenNames tpenv e = { envinner with eLambdaArgInfos = rest } | [] -> envinner - let bodyExpr, tpenv = TcIteratedLambdas cenv false envinner resultTy takenNames tpenv bodyExpr + let bodyExpr, tpenv = TcIteratedLambdas cenv false envinner (MustConvertTo (false, resultTy)) takenNames tpenv bodyExpr // See bug 5758: Non-monotonicity in inference: need to ensure that parameters are never inferred to have byref type, instead it is always declared byrefs |> Map.iter (fun _ (orig, v) -> if not orig && isByrefTy cenv.g v.Type then errorR(Error(FSComp.SR.tcParameterInferredByref v.DisplayName, v.Range))) @@ -5883,10 +6061,8 @@ and TcIteratedLambdas cenv isFirst (env: TcEnv) overallTy takenNames tpenv e = | e -> // Dive into the expression to check for syntax errors and suppress them if they show. conditionallySuppressErrorReporting (not isFirst && synExprContainsError e) (fun () -> - //TcExprFlex cenv true true overallTy env tpenv e) TcExpr cenv overallTy env tpenv e) - // Check expr.[idx] // This is a little over complicated for my liking. Basically we want to interpret e1.[idx] as e1.Item(idx). // However it's not so simple as all that. First "Item" can have a different name according to an attribute in @@ -6110,10 +6286,10 @@ and TcNewExpr cenv env tpenv objTy mObjTyOpt superInit arg mWholeExprOrObjTy = if not (isAppTy cenv.g objTy) && not (isAnyTupleTy cenv.g objTy) then error(Error(FSComp.SR.tcNamedTypeRequired(if superInit then "inherit" else "new"), mWholeExprOrObjTy)) let item = ForceRaise (ResolveObjectConstructor cenv.nameResolver env.DisplayEnv mWholeExprOrObjTy ad objTy) - TcCtorCall false cenv env tpenv objTy objTy mObjTyOpt item superInit [arg] mWholeExprOrObjTy [] None + TcCtorCall false cenv env tpenv (MustEqual objTy) objTy mObjTyOpt item superInit [arg] mWholeExprOrObjTy [] None /// Check an 'inheritedTys declaration in an implicit or explicit class -and TcCtorCall isNaked cenv env tpenv overallTy objTy mObjTyOpt item superInit args mWholeCall delayed afterTcOverloadResolutionOpt = +and TcCtorCall isNaked cenv env tpenv (overallTy: OverallTy) objTy mObjTyOpt item superInit args mWholeCall delayed afterTcOverloadResolutionOpt = let ad = env.AccessRights let isSuperInit = (if superInit then CtorValUsedAsSuperInit else NormalValUse) let mItem = match mObjTyOpt with Some m -> m | None -> mWholeCall @@ -6145,14 +6321,13 @@ and TcCtorCall isNaked cenv env tpenv overallTy objTy mObjTyOpt item superInit a match mObjTyOpt with | Some mObjTy -> CallNameResolutionSink cenv.tcSink (mObjTy, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.AccessRights) | None -> () - TcNewDelegateThen cenv objTy env tpenv mItem mWholeCall ty arg ExprAtomicFlag.NonAtomic delayed + TcNewDelegateThen cenv (MustEqual objTy) env tpenv mItem mWholeCall ty arg ExprAtomicFlag.NonAtomic delayed | _ -> error(Error(FSComp.SR.tcSyntaxCanOnlyBeUsedToCreateObjectTypes(if superInit then "inherit" else "new"), mWholeCall)) - // Check a record construction expression -and TcRecordConstruction cenv overallTy env tpenv optOrigExprInfo objTy fldsList m = +and TcRecordConstruction cenv (overallTy: TType) env tpenv optOrigExprInfo objTy fldsList m = let tcref, tinst = destAppTy cenv.g objTy let tycon = tcref.Deref UnifyTypes cenv env m overallTy objTy @@ -6467,17 +6642,15 @@ and CheckSuperType cenv ty m = errorR(Error(FSComp.SR.tcCannotInheritFromErasedType(), m)) -and TcObjectExpr cenv overallTy env tpenv (synObjTy, argopt, binds, extraImpls, mNewExpr, mWholeExpr) = - let mObjTy = synObjTy.Range +and TcObjectExpr cenv env tpenv (objTy, realObjTy, argopt, binds, extraImpls, mObjTy, mNewExpr, mWholeExpr) = - let objTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synObjTy match tryTcrefOfAppTy cenv.g objTy with | ValueNone -> error(Error(FSComp.SR.tcNewMustBeUsedWithNamedType(), mNewExpr)) | ValueSome tcref -> let isRecordTy = tcref.IsRecordTycon if not isRecordTy && not (isInterfaceTy cenv.g objTy) && isSealedTy cenv.g objTy then errorR(Error(FSComp.SR.tcCannotCreateExtensionOfSealedType(), mNewExpr)) - CheckSuperType cenv objTy synObjTy.Range + CheckSuperType cenv objTy mObjTy // Add the object type to the ungeneralizable items let env = {env with eUngeneralizableItems = addFreeItemOfTy objTy env.eUngeneralizableItems } @@ -6501,34 +6674,21 @@ and TcObjectExpr cenv overallTy env tpenv (synObjTy, argopt, binds, extraImpls, | NormalizedBinding (_, _, _, _, [], _, _, _, SynPat.Named(id, _, _, _), NormalizedBindingRhs(_, _, rhsExpr), _, _) -> id.idText, rhsExpr | _ -> error(Error(FSComp.SR.tcOnlySimpleBindingsCanBeUsedInConstructionExpressions(), b.RangeOfBindingWithoutRhs))) - TcRecordConstruction cenv overallTy env tpenv None objTy fldsList mWholeExpr + TcRecordConstruction cenv objTy env tpenv None objTy fldsList mWholeExpr else let item = ForceRaise (ResolveObjectConstructor cenv.nameResolver env.DisplayEnv mObjTy ad objTy) if isFSharpObjModelTy cenv.g objTy && GetCtorShapeCounter env = 1 then error(Error(FSComp.SR.tcObjectsMustBeInitializedWithObjectExpression(), mNewExpr)) - // Work out the type of any interfaces to implement - let extraImpls, tpenv = - (tpenv, extraImpls) ||> List.mapFold (fun tpenv (SynInterfaceImpl(synIntfTy, overrides, m)) -> - let intfTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synIntfTy - if not (isInterfaceTy cenv.g intfTy) then - error(Error(FSComp.SR.tcExpectedInterfaceType(), m)) - if isErasedType cenv.g intfTy then - errorR(Error(FSComp.SR.tcCannotInheritFromErasedType(), m)) - (m, intfTy, overrides), tpenv) - - let realObjTy = if isObjTy cenv.g objTy && not (isNil extraImpls) then (p23 (List.head extraImpls)) else objTy - UnifyTypes cenv env mWholeExpr overallTy realObjTy - let ctorCall, baseIdOpt, tpenv = match item, argopt with | Item.CtorGroup(methodName, minfos), Some (arg, baseIdOpt) -> let meths = minfos |> List.map (fun minfo -> minfo, None) - let afterResolution = ForNewConstructors cenv.tcSink env synObjTy.Range methodName minfos + let afterResolution = ForNewConstructors cenv.tcSink env mObjTy methodName minfos let ad = env.AccessRights - let expr, tpenv = TcMethodApplicationThen cenv env objTy None tpenv None [] mWholeExpr mObjTy methodName ad PossiblyMutates false meths afterResolution CtorValUsedAsSuperInit [arg] ExprAtomicFlag.Atomic [] + let expr, tpenv = TcMethodApplicationThen cenv env (MustEqual objTy) None tpenv None [] mWholeExpr mObjTy methodName ad PossiblyMutates false meths afterResolution CtorValUsedAsSuperInit [arg] ExprAtomicFlag.Atomic [] // The 'base' value is always bound let baseIdOpt = (match baseIdOpt with None -> Some(ident("base", mObjTy)) | Some id -> Some id) expr, baseIdOpt, tpenv @@ -6550,6 +6710,7 @@ and TcObjectExpr cenv overallTy env tpenv (synObjTy, argopt, binds, extraImpls, let overridesAndVirts, tpenv = ComputeObjectExprOverrides cenv env tpenv impls + // 2. check usage conditions overridesAndVirts |> List.iter (fun (m, implty, dispatchSlots, dispatchSlotsKeyed, availPriorOverrides, overrides) -> let overrideSpecs = overrides |> List.map fst @@ -6557,7 +6718,7 @@ and TcObjectExpr cenv overallTy env tpenv (synObjTy, argopt, binds, extraImpls, DispatchSlotChecking.CheckDispatchSlotsAreImplemented (env.DisplayEnv, cenv.infoReader, m, env.NameEnv, cenv.tcSink, false, implty, dispatchSlots, availPriorOverrides, overrideSpecs) |> ignore) - // 6c. create the specs of overrides + // 3. create the specs of overrides let allTypeImpls = overridesAndVirts |> List.map (fun (m, implty, _, dispatchSlotsKeyed, _, overrides) -> let overrides' = @@ -6577,12 +6738,13 @@ and TcObjectExpr cenv overallTy env tpenv (synObjTy, argopt, binds, extraImpls, let overridden = match searchForOverride with | Some x -> x - | None -> error(Error(FSComp.SR.tcAtLeastOneOverrideIsInvalid(), synObjTy.Range)) + | None -> error(Error(FSComp.SR.tcAtLeastOneOverrideIsInvalid(), mObjTy)) yield TObjExprMethod(overridden.GetSlotSig(cenv.amap, m), bindingAttribs, mtps, [thisVal] :: methodVars, bindingBody, id.idRange) ] (implty, overrides')) let objTy', overrides' = allTypeImpls.Head + assert (typeEquiv cenv.g objTy objTy') let extraImpls = allTypeImpls.Tail // 7. Build the implementation @@ -6590,21 +6752,19 @@ and TcObjectExpr cenv overallTy env tpenv (synObjTy, argopt, binds, extraImpls, let expr = mkCoerceIfNeeded cenv.g realObjTy objTy' expr expr, tpenv - - //------------------------------------------------------------------------- // TcConstStringExpr //------------------------------------------------------------------------- /// Check a constant string expression. It might be a 'printf' format string -and TcConstStringExpr cenv overallTy env m tpenv s = +and TcConstStringExpr cenv (overallTy: OverallTy) env m tpenv s = - if (AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy cenv.g.string_ty) then + if (AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy.Commit cenv.g.string_ty) then mkString cenv.g m s, tpenv else TcFormatStringExpr cenv overallTy env m tpenv s -and TcFormatStringExpr cenv overallTy env m tpenv (fmtString: string) = +and TcFormatStringExpr cenv (overallTy: OverallTy) env m tpenv (fmtString: string) = let g = cenv.g let aty = NewInferenceType () let bty = NewInferenceType () @@ -6614,7 +6774,7 @@ and TcFormatStringExpr cenv overallTy env m tpenv (fmtString: string) = let formatTy = mkPrintfFormatTy g aty bty cty dty ety // This might qualify as a format string - check via a type directed rule - let ok = not (isObjTy g overallTy) && AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy formatTy + let ok = not (isObjTy g overallTy.Commit) && AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy.Commit formatTy if ok then // Parse the format string to work out the phantom types @@ -6637,11 +6797,12 @@ and TcFormatStringExpr cenv overallTy env m tpenv (fmtString: string) = fmtExpr, tpenv else - UnifyTypes cenv env m overallTy g.string_ty - mkString g m fmtString, tpenv + TcPropagatingExprLeafThenConvert cenv overallTy g.string_ty env (* true *) m (fun () -> + mkString g m fmtString, tpenv + ) /// Check an interpolated string expression -and TcInterpolatedStringExpr cenv overallTy env m tpenv (parts: SynInterpolatedStringPart list) = +and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: SynInterpolatedStringPart list) = let g = cenv.g let synFillExprs = @@ -6675,12 +6836,12 @@ and TcInterpolatedStringExpr cenv overallTy env m tpenv (parts: SynInterpolatedS let stringKind = // If this is an interpolated string then try to force the result to be a string - if (AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy g.string_ty) then + if (AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy.Commit g.string_ty) then // And if that succeeds, the result of printing is a string UnifyTypes cenv env m printerArgTy g.unit_ty UnifyTypes cenv env m printerResidueTy g.string_ty - UnifyTypes cenv env m printerResultTy overallTy + UnifyTypes cenv env m printerResultTy overallTy.Commit // And if that succeeds, the printerTy and printerResultTy must be the same (there are no curried arguments) UnifyTypes cenv env m printerTy printerResultTy @@ -6688,14 +6849,14 @@ and TcInterpolatedStringExpr cenv overallTy env m tpenv (parts: SynInterpolatedS Choice1Of2 (true, newFormatMethod) // ... or if that fails then may be a FormattableString by a type-directed rule.... - elif (not (isObjTy g overallTy) && - ((g.system_FormattableString_tcref.CanDeref && AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy g.system_FormattableString_ty) - || (g.system_IFormattable_tcref.CanDeref && AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy g.system_IFormattable_ty))) then + elif (not (isObjTy g overallTy.Commit) && + ((g.system_FormattableString_tcref.CanDeref && AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy.Commit g.system_FormattableString_ty) + || (g.system_IFormattable_tcref.CanDeref && AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy.Commit g.system_IFormattable_ty))) then // And if that succeeds, the result of printing is a string UnifyTypes cenv env m printerArgTy g.unit_ty UnifyTypes cenv env m printerResidueTy g.string_ty - UnifyTypes cenv env m printerResultTy overallTy + UnifyTypes cenv env m printerResultTy overallTy.Commit // Find the FormattableStringFactor.Create method in the .NET libraries let ad = env.eAccessRights @@ -6709,15 +6870,13 @@ and TcInterpolatedStringExpr cenv overallTy env m tpenv (parts: SynInterpolatedS | None -> languageFeatureNotSupportedInLibraryError cenv.g.langVersion LanguageFeature.StringInterpolation m // ... or if that fails then may be a PrintfFormat by a type-directed rule.... - elif not (isObjTy g overallTy) && AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy formatTy then + elif not (isObjTy g overallTy.Commit) && AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy.Commit formatTy then // And if that succeeds, the printerTy and printerResultTy must be the same (there are no curried arguments) UnifyTypes cenv env m printerTy printerResultTy Choice1Of2 (false, newFormatMethod) else - // this should fail and produce an error - UnifyTypes cenv env m overallTy g.string_ty Choice1Of2 (true, newFormatMethod) let isFormattableString = (match stringKind with Choice2Of2 _ -> true | _ -> false) @@ -6777,6 +6936,8 @@ and TcInterpolatedStringExpr cenv overallTy env m tpenv (parts: SynInterpolatedS UnifyTypes cenv env m printerTupleTy printerTupleTyRequired + // Type check the expressions filling the holes + if List.isEmpty synFillExprs then let str = mkString g m printfFormatString @@ -6787,7 +6948,7 @@ and TcInterpolatedStringExpr cenv overallTy env m tpenv (parts: SynInterpolatedS else // Type check the expressions filling the holes let flexes = argTys |> List.map (fun _ -> false) - let fillExprs, tpenv = TcExprs cenv env m tpenv flexes argTys synFillExprs + let fillExprs, tpenv = TcExprsWithFlexes cenv env m tpenv flexes argTys synFillExprs let fillExprsBoxed = (argTys, fillExprs) ||> List.map2 (mkCallBox g m) @@ -6802,8 +6963,10 @@ and TcInterpolatedStringExpr cenv overallTy env m tpenv (parts: SynInterpolatedS let fmtExpr = MakeMethInfoCall cenv.amap m newFormatMethod [] [mkString g m printfFormatString; argsExpr; percentATysExpr] if isString then - // Make the call to sprintf - mkCall_sprintf g m printerTy fmtExpr [], tpenv + TcPropagatingExprLeafThenConvert cenv overallTy g.string_ty env (* true *) m (fun () -> + // Make the call to sprintf + mkCall_sprintf g m printerTy fmtExpr [], tpenv + ) else fmtExpr, tpenv @@ -6812,7 +6975,7 @@ and TcInterpolatedStringExpr cenv overallTy env m tpenv (parts: SynInterpolatedS // Type check the expressions filling the holes let flexes = argTys |> List.map (fun _ -> false) - let fillExprs, tpenv = TcExprs cenv env m tpenv flexes argTys synFillExprs + let fillExprs, tpenv = TcExprsWithFlexes cenv env m tpenv flexes argTys synFillExprs let fillExprsBoxed = (argTys, fillExprs) ||> List.map2 (mkCallBox g m) @@ -6823,7 +6986,7 @@ and TcInterpolatedStringExpr cenv overallTy env m tpenv (parts: SynInterpolatedS let createExpr, _ = BuildPossiblyConditionalMethodCall cenv env NeverMutates m false createFormattableStringMethod NormalValUse [] [dotnetFormatStringExpr; argsExpr] [] let resultExpr = - if typeEquiv g overallTy g.system_IFormattable_ty then + if typeEquiv g overallTy.Commit g.system_IFormattable_ty then mkCoerceIfNeeded g g.system_IFormattable_ty g.system_FormattableString_ty createExpr else createExpr @@ -6834,16 +6997,18 @@ and TcInterpolatedStringExpr cenv overallTy env m tpenv (parts: SynInterpolatedS //------------------------------------------------------------------------- /// Check a constant expression. -and TcConstExpr cenv overallTy env m tpenv c = +and TcConstExpr cenv (overallTy: OverallTy) env m tpenv c = match c with - // NOTE: these aren't "really" constants | SynConst.Bytes (bytes, _, m) -> - UnifyTypes cenv env m overallTy (mkByteArrayTy cenv.g) + let actualTy = mkByteArrayTy cenv.g + TcPropagatingExprLeafThenConvert cenv overallTy actualTy env (* true *) m <| fun ()-> Expr.Op (TOp.Bytes bytes, [], [], m), tpenv | SynConst.UInt16s arr -> - UnifyTypes cenv env m overallTy (mkArrayType cenv.g cenv.g.uint16_ty); Expr.Op (TOp.UInt16s arr, [], [], m), tpenv + let actualTy = mkArrayType cenv.g cenv.g.uint16_ty + TcPropagatingExprLeafThenConvert cenv overallTy actualTy env (* true *) m <| fun () -> + Expr.Op (TOp.UInt16s arr, [], [], m), tpenv | SynConst.UserNum (s, suffix) -> let expr = @@ -6878,9 +7043,10 @@ and TcConstExpr cenv overallTy env m tpenv c = TcExpr cenv overallTy env tpenv expr | _ -> - let c' = TcConst cenv overallTy m env c - Expr.Const (c', m, overallTy), tpenv - + TcNonPropagatingExprLeafThenConvert cenv overallTy env m (fun () -> + let cTy = NewInferenceType() + let c' = TcConst cenv cTy m env c + Expr.Const (c', m, cTy), cTy, tpenv) //------------------------------------------------------------------------- // TcAssertExpr @@ -6895,8 +7061,7 @@ and TcAssertExpr cenv overallTy env (m: range) tpenv x = TcExpr cenv overallTy env tpenv callDiagnosticsExpr - -and TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr) = +and TcRecdExpr cenv (overallTy: TType) env tpenv (inherits, optOrigExpr, flds, mWholeExpr) = let requiresCtor = (GetCtorShapeCounter env = 1) // Get special expression forms for constructors let haveCtor = Option.isSome inherits @@ -6908,7 +7073,7 @@ and TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr match inherits with | Some (_, _, mInherits, _, _) -> error(Error(FSComp.SR.tcInvalidRecordConstruction(), mInherits)) | None -> - let olde, tpenv = TcExpr cenv overallTy env tpenv origExpr + let olde, tpenv = TcExpr cenv (MustEqual overallTy) env tpenv origExpr Some olde, tpenv let hasOrigExpr = optOrigExpr.IsSome @@ -6966,7 +7131,7 @@ and TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr match inherits, GetSuperTypeOfType cenv.g cenv.amap mWholeExpr overallTy with | Some (superTy, arg, m, _, _), Some realSuperTy -> // Constructor expression, with an explicit 'inheritedTys clause. Check the inherits clause. - let e, tpenv = TcExpr cenv realSuperTy env tpenv (SynExpr.New (true, superTy, arg, m)) + let e, tpenv = TcExpr cenv (MustEqual realSuperTy) env tpenv (SynExpr.New (true, superTy, arg, m)) Some e, tpenv | None, Some realSuperTy when requiresCtor -> // Constructor expression, No 'inherited' clause, hence look for a default constructor @@ -6989,7 +7154,7 @@ and TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr // Check '{| .... |}' -and TcAnonRecdExpr cenv overallTy env tpenv (isStruct, optOrigSynExpr, unsortedFieldIdsAndSynExprsGiven, mWholeExpr) = +and TcAnonRecdExpr cenv (overallTy: TType) env tpenv (isStruct, optOrigSynExpr, unsortedFieldIdsAndSynExprsGiven, mWholeExpr) = let unsortedFieldSynExprsGiven = List.map snd unsortedFieldIdsAndSynExprsGiven match optOrigSynExpr with @@ -7019,7 +7184,7 @@ and TcAnonRecdExpr cenv overallTy env tpenv (isStruct, optOrigSynExpr, unsortedF let flexes = unsortedFieldTys |> List.map (fun _ -> true) - let unsortedCheckedArgs, tpenv = TcExprs cenv env mWholeExpr tpenv flexes unsortedFieldTys unsortedFieldSynExprsGiven + let unsortedCheckedArgs, tpenv = TcExprsWithFlexes cenv env mWholeExpr tpenv flexes unsortedFieldTys unsortedFieldSynExprsGiven mkAnonRecd cenv.g mWholeExpr anonInfo unsortedFieldIds unsortedCheckedArgs unsortedFieldTys, tpenv @@ -7034,7 +7199,7 @@ and TcAnonRecdExpr cenv overallTy env tpenv (isStruct, optOrigSynExpr, unsortedF // Unlike in the case of record type copy-and-update {| a with X = 1 |} does not force a.X to exist or have had type 'int' let origExprTy = NewInferenceType() - let origExprChecked, tpenv = TcExpr cenv origExprTy env tpenv origExpr + let origExprChecked, tpenv = TcExpr cenv (MustEqual origExprTy) env tpenv origExpr let oldv, oldve = mkCompGenLocal mWholeExpr "inputRecord" origExprTy let mOrigExpr = origExpr.Range @@ -7104,7 +7269,7 @@ and TcAnonRecdExpr cenv overallTy env tpenv (isStruct, optOrigSynExpr, unsortedF // Check the expressions in unsorted order let unsortedFieldExprsGiven, tpenv = - TcExprs cenv env mWholeExpr tpenv flexes unsortedFieldTysGiven unsortedFieldSynExprsGiven + TcExprsWithFlexes cenv env mWholeExpr tpenv flexes unsortedFieldTysGiven unsortedFieldSynExprsGiven let unsortedFieldExprsGiven = unsortedFieldExprsGiven |> List.toArray @@ -7128,7 +7293,6 @@ and TcAnonRecdExpr cenv overallTy env tpenv (isStruct, optOrigSynExpr, unsortedF let expr = mkCompGenLet mOrigExpr oldv origExprChecked expr expr, tpenv - and TcForEachExpr cenv overallTy env tpenv (pat, enumSynExpr, bodySynExpr, mWholeExpr, spForLoop) = let tryGetOptimizeSpanMethodsAux g m ty isReadOnlySpan = match (if isReadOnlySpan then tryDestReadOnlySpanTy g m ty else tryDestSpanTy g m ty) with @@ -7149,7 +7313,7 @@ and TcForEachExpr cenv overallTy env tpenv (pat, enumSynExpr, bodySynExpr, mWhol else tryGetOptimizeSpanMethodsAux g m ty true - UnifyTypes cenv env mWholeExpr overallTy cenv.g.unit_ty + UnifyTypes cenv env mWholeExpr overallTy.Commit cenv.g.unit_ty let mPat = pat.Range //let mBodyExpr = bodySynExpr.Range @@ -7230,11 +7394,11 @@ and TcForEachExpr cenv overallTy env tpenv (pat, enumSynExpr, bodySynExpr, mWhol // Add the pattern match compilation let bodyExpr = let valsDefinedByMatching = ListSet.remove valEq elemVar vspecs - CompilePatternForMatch - cenv env enumSynExpr.Range pat.Range false IgnoreWithWarning (elemVar, [], None) + CompilePatternForMatch + cenv env enumSynExpr.Range pat.Range false IgnoreWithWarning (elemVar, [], None) [TClause(pat, None, TTarget(valsDefinedByMatching, bodyExpr, DebugPointForTarget.Yes, None), mForLoopStart)] - enumElemTy - overallTy + enumElemTy + overallTy.Commit // Apply the fixup to bind the elemVar if needed let bodyExpr = bodyExprFixup elemVar bodyExpr @@ -7279,13 +7443,13 @@ and TcQuotationExpr cenv overallTy env tpenv (_oper, raw, ast, isFromQueryExpres let astTy = NewInferenceType () // Assert the overall type for the domain of the quotation template - UnifyTypes cenv env m overallTy (if raw then mkRawQuotedExprTy cenv.g else mkQuotedExprTy cenv.g astTy) + UnifyTypes cenv env m overallTy.Commit (if raw then mkRawQuotedExprTy cenv.g else mkQuotedExprTy cenv.g astTy) // Check the expression - let expr, tpenv = TcExpr cenv astTy env tpenv ast + let expr, tpenv = TcExpr cenv (MustEqual astTy) env tpenv ast // Wrap the expression - let expr = Expr.Quote (expr, ref None, isFromQueryExpression, m, overallTy) + let expr = Expr.Quote (expr, ref None, isFromQueryExpression, m, overallTy.Commit) // Coerce it if needed let expr = if raw then mkCoerceExpr(expr, (mkRawQuotedExprTy cenv.g), m, (tyOfExpr cenv.g expr)) else expr @@ -7302,7 +7466,7 @@ and TcQuotationExpr cenv overallTy env tpenv (_oper, raw, ast, isFromQueryExpres /// /// We propagate information from the expected overall type 'overallTy'. The use /// of function application syntax unambiguously implies that 'overallTy' is a function type. -and Propagate cenv overallTy env tpenv (expr: ApplicableExpr) exprty delayed = +and Propagate cenv (overallTy: OverallTy) (env: TcEnv) tpenv (expr: ApplicableExpr) exprty delayed = let rec propagate isAddrOf delayedList mExpr exprty = match delayedList with @@ -7317,13 +7481,14 @@ and Propagate cenv overallTy env tpenv (expr: ApplicableExpr) exprty delayed = mkByrefTyWithInference cenv.g (destByrefTy cenv.g exprty) (NewByRefKindInferenceType cenv.g mExpr) elif isByrefTy cenv.g exprty then // Implicit dereference on byref on return - if isByrefTy cenv.g overallTy then + if isByrefTy cenv.g overallTy.Commit then errorR(Error(FSComp.SR.tcByrefReturnImplicitlyDereferenced(), mExpr)) destByrefTy cenv.g exprty else exprty - UnifyTypesAndRecover cenv env mExpr overallTy exprty + // at the end of the application chain allow coercion introduction + UnifyOverallTypeAndRecover cenv env mExpr overallTy exprty | DelayedDot :: _ | DelayedSet _ :: _ @@ -7358,26 +7523,26 @@ and Propagate cenv overallTy env tpenv (expr: ApplicableExpr) exprty delayed = if IsIndexerType cenv.g cenv.amap expr.Type then match expr.Expr with | Expr.Val (d, _, _) -> - error (NotAFunctionButIndexer(denv, overallTy, Some d.DisplayName, mExpr, mArg)) + error (NotAFunctionButIndexer(denv, overallTy.Commit, Some d.DisplayName, mExpr, mArg)) | _ -> - error (NotAFunctionButIndexer(denv, overallTy, None, mExpr, mArg)) + error (NotAFunctionButIndexer(denv, overallTy.Commit, None, mExpr, mArg)) else - error (NotAFunction(denv, overallTy, mExpr, mArg)) + error (NotAFunction(denv, overallTy.Commit, mExpr, mArg)) | _ -> // 'delayed' is about to be dropped on the floor, first do rudimentary checking to get name resolutions in its body RecordNameAndTypeResolutions_IdeallyWithoutHavingOtherEffects_Delayed cenv env tpenv delayed - error (NotAFunction(denv, overallTy, mExpr, mArg)) + error (NotAFunction(denv, overallTy.Commit, mExpr, mArg)) propagate false delayed expr.Range exprty -and PropagateThenTcDelayed cenv overallTy env tpenv mExpr expr exprty (atomicFlag: ExprAtomicFlag) delayed = +and PropagateThenTcDelayed cenv (overallTy: OverallTy) env tpenv mExpr expr exprty (atomicFlag: ExprAtomicFlag) delayed = Propagate cenv overallTy env tpenv expr exprty delayed TcDelayed cenv overallTy env tpenv mExpr expr exprty atomicFlag delayed /// Typecheck "expr ... " constructs where "..." is a sequence of applications, /// type applications and dot-notation projections. -and TcDelayed cenv overallTy env tpenv mExpr expr exprty (atomicFlag: ExprAtomicFlag) delayed = +and TcDelayed cenv (overallTy: OverallTy) env tpenv mExpr expr exprty (atomicFlag: ExprAtomicFlag) delayed = // OK, we've typechecked the thing on the left of the delayed lookup chain. // We can now record for posterity the type of this expression and the location of the expression. @@ -7387,8 +7552,11 @@ and TcDelayed cenv overallTy env tpenv mExpr expr exprty (atomicFlag: ExprAtomic match delayed with | [] | DelayedDot :: _ -> - UnifyTypes cenv env mExpr overallTy exprty - expr.Expr, tpenv + // at the end of the application chain allow coercion introduction + UnifyOverallType cenv env mExpr overallTy exprty + let expr2 = TcAdjustExprForTypeDirectedConversions cenv overallTy exprty env (* true *) mExpr expr.Expr + expr2, tpenv + // Expr.M (args) where x.M is a .NET method or index property // expr.M(args) where x.M is a .NET method or index property // expr.M where x.M is a .NET method or index property @@ -7402,7 +7570,7 @@ and TcDelayed cenv overallTy env tpenv mExpr expr exprty (atomicFlag: ExprAtomic error(Error(FSComp.SR.tcUnexpectedTypeArguments(), mTypeArgs)) | DelayedSet (synExpr2, mStmt) :: otherDelayed -> if not (isNil otherDelayed) then error(Error(FSComp.SR.tcInvalidAssignment(), mExpr)) - UnifyTypes cenv env mExpr overallTy cenv.g.unit_ty + UnifyTypes cenv env mExpr overallTy.Commit cenv.g.unit_ty let expr = expr.Expr let _wrap, exprAddress, _readonly, _writeonly = mkExprAddrOfExpr cenv.g true false DefinitelyMutates expr None mExpr let vty = tyOfExpr cenv.g expr @@ -7469,7 +7637,7 @@ and TcNameOfExpr cenv env tpenv (synArg: SynExpr) = | Item.CtorGroup _ | Item.FakeInterfaceCtor _ -> false | _ -> true) -> - let overallTy = match overallTyOpt with None -> NewInferenceType() | Some t -> t + let overallTy = match overallTyOpt with None -> MustEqual (NewInferenceType()) | Some t -> t let _, _ = TcItemThen cenv overallTy env tpenv res delayed true | _ -> @@ -7524,9 +7692,9 @@ and TcNameOfExpr cenv env tpenv (synArg: SynExpr) = check overallTyOpt resultOpt expr delayed // expr : type" allowed with no subsequent qualifications - | SynExpr.Typed (synBodyExpr, synType, _m) when delayed.IsEmpty && overallTyOpt.IsNone -> - let tgtTy, _tpenv = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synType - check (Some tgtTy) resultOpt synBodyExpr delayed + | SynExpr.Typed (synBodyExpr, synType, _) when delayed.IsEmpty && overallTyOpt.IsNone -> + let tgtTy, _tpenv = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synType + check (Some (MustEqual tgtTy)) resultOpt synBodyExpr delayed | _ -> error (Error(FSComp.SR.expressionHasNoName(), m)) @@ -7542,7 +7710,7 @@ and TcNameOfExprResult cenv (lastIdent: Ident) m = // TcFunctionApplicationThen: Typecheck "expr x" + projections //------------------------------------------------------------------------- -and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty (synArg: SynExpr) atomicFlag delayed = +and TcFunctionApplicationThen cenv (overallTy: OverallTy) env tpenv mExprAndArg expr exprty (synArg: SynExpr) atomicFlag delayed = let denv = env.DisplayEnv let mArg = synArg.Range let mFunExpr = expr.Range @@ -7568,7 +7736,7 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( | _ -> false) | _ -> () - let arg, tpenv = TcExpr cenv domainTy env tpenv synArg + let arg, tpenv = TcExprFlex2 cenv domainTy env false tpenv synArg let exprAndArg, resultTy = buildApp cenv expr resultTy arg mExprAndArg TcDelayed cenv overallTy env tpenv mExprAndArg exprAndArg resultTy atomicFlag delayed @@ -7579,7 +7747,7 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( let bodyOfCompExpr, tpenv = cenv.TcComputationExpression cenv env overallTy tpenv (mFunExpr, expr.Expr, exprty, comp) TcDelayed cenv overallTy env tpenv mExprAndArg (MakeApplicableExprNoFlex cenv bodyOfCompExpr) (tyOfExpr cenv.g bodyOfCompExpr) ExprAtomicFlag.NonAtomic delayed | _ -> - error (NotAFunction(denv, overallTy, mFunExpr, mArg)) + error (NotAFunction(denv, overallTy.Commit, mFunExpr, mArg)) //------------------------------------------------------------------------- // TcLongIdentThen: Typecheck "A.B.C.E.F ... " constructs @@ -7601,7 +7769,7 @@ and GetLongIdentTypeNameInfo delayed = | _ -> TypeNameResolutionInfo.Default -and TcLongIdentThen cenv overallTy env tpenv (LongIdentWithDots(longId, _)) delayed = +and TcLongIdentThen cenv (overallTy: OverallTy) env tpenv (LongIdentWithDots(longId, _)) delayed = let ad = env.eAccessRights let typeNameResInfo = GetLongIdentTypeNameInfo delayed @@ -7614,7 +7782,7 @@ and TcLongIdentThen cenv overallTy env tpenv (LongIdentWithDots(longId, _)) dela // Typecheck "item+projections" //------------------------------------------------------------------------- *) // mItem is the textual range covered by the long identifiers that make up the item -and TcItemThen cenv overallTy env tpenv (tinstEnclosing, item, mItem, rest, afterResolution) delayed = +and TcItemThen cenv (overallTy: OverallTy) env tpenv (tinstEnclosing, item, mItem, rest, afterResolution) delayed = let g = cenv.g let delayed = delayRest rest mItem delayed let ad = env.eAccessRights @@ -7639,6 +7807,7 @@ and TcItemThen cenv overallTy env tpenv (tinstEnclosing, item, mItem, rest, afte | _ -> ApplyUnionCaseOrExnTypes mItem cenv env ucaseAppTy item let numArgTys = List.length argTys + // Subsumption at data constructions if argument type is nominal prior to equations for any arguments or return types let flexes = argTys |> List.map (isTyparTy g >> not) @@ -7655,7 +7824,7 @@ and TcItemThen cenv overallTy env tpenv (tinstEnclosing, item, mItem, rest, afte | DelayedApp (atomicFlag, (FittedArgs args as origArg), mExprAndArg) :: otherDelayed -> // assert the overall result type if possible if isNil otherDelayed then - UnifyTypes cenv env mExprAndArg overallTy ucaseAppTy + UnifyOverallType cenv env mExprAndArg overallTy ucaseAppTy let numArgs = List.length args UnionCaseOrExnCheck env numArgTys numArgs mExprAndArg @@ -7729,7 +7898,7 @@ and TcItemThen cenv overallTy env tpenv (tinstEnclosing, item, mItem, rest, afte assert (Seq.forall (box >> ((<>) null) ) fittedArgs) List.ofArray fittedArgs - let args', tpenv = TcExprs cenv env mExprAndArg tpenv flexes argTys args + let args', tpenv = TcExprsWithFlexes cenv env mExprAndArg tpenv flexes argTys args PropagateThenTcDelayed cenv overallTy env tpenv mExprAndArg (MakeApplicableExprNoFlex cenv (mkConstrApp mExprAndArg args')) ucaseAppTy atomicFlag otherDelayed | DelayedTypeApp (_x, mTypeArgs, _mExprAndTypeArgs) :: _delayed' -> @@ -7998,9 +8167,9 @@ and TcItemThen cenv overallTy env tpenv (tinstEnclosing, item, mItem, rest, afte let delayed1, delayed2 = let pred = (function DelayedApp (_, arg, _) -> isSimpleArgument arg | _ -> false) List.takeWhile pred delayed, List.skipWhile pred delayed - let intermediateTy = if isNil delayed2 then overallTy else NewInferenceType () + let intermediateTy = if isNil delayed2 then overallTy.Commit else NewInferenceType () - let resultExpr, tpenv = TcDelayed cenv intermediateTy env tpenv mItem (MakeApplicableExprNoFlex cenv expr) (tyOfExpr g expr) ExprAtomicFlag.NonAtomic delayed1 + let resultExpr, tpenv = TcDelayed cenv (MustEqual intermediateTy) env tpenv mItem (MakeApplicableExprNoFlex cenv expr) (tyOfExpr g expr) ExprAtomicFlag.NonAtomic delayed1 // Add the constraint after the application arguments have been checked to allow annotations to kick in on rigid type parameters AddCxMethodConstraint env.DisplayEnv cenv.css mItem NoTrace traitInfo @@ -8030,7 +8199,7 @@ and TcItemThen cenv overallTy env tpenv (tinstEnclosing, item, mItem, rest, afte // Mutable value set: 'v <- e' | DelayedSet(e2, mStmt) :: otherDelayed -> if not (isNil otherDelayed) then error(Error(FSComp.SR.tcInvalidAssignment(), mStmt)) - UnifyTypes cenv env mStmt overallTy g.unit_ty + UnifyTypes cenv env mStmt overallTy.Commit g.unit_ty vref.Deref.SetHasBeenReferenced() CheckValAccessible mItem env.AccessRights vref CheckValAttributes g vref mItem |> CommitOperationResult @@ -8101,7 +8270,7 @@ and TcItemThen cenv overallTy env tpenv (tinstEnclosing, item, mItem, rest, afte | DelayedSet(e2, mStmt) :: otherDelayed -> if not (isNil otherDelayed) then error(Error(FSComp.SR.tcInvalidAssignment(), mStmt)) // Static Property Set (possibly indexer) - UnifyTypes cenv env mStmt overallTy g.unit_ty + UnifyTypes cenv env mStmt overallTy.Commit g.unit_ty let meths = pinfos |> SettersOfPropInfos if meths.IsEmpty then let meths = pinfos |> GettersOfPropInfos @@ -8131,7 +8300,7 @@ and TcItemThen cenv overallTy env tpenv (tinstEnclosing, item, mItem, rest, afte let exprty = finfo.FieldType(cenv.amap, mItem) match delayed with | DelayedSet(e2, mStmt) :: _delayed' -> - UnifyTypes cenv env mStmt overallTy g.unit_ty + UnifyTypes cenv env mStmt overallTy.Commit g.unit_ty // Always allow subsumption on assignment to fields let e2', tpenv = TcExprFlex cenv true false exprty env tpenv e2 let expr = BuildILStaticFieldSet mStmt finfo e2' @@ -8168,7 +8337,7 @@ and TcItemThen cenv overallTy env tpenv (tinstEnclosing, item, mItem, rest, afte // Set static F# field CheckRecdFieldMutation mItem env.DisplayEnv rfinfo - UnifyTypes cenv env mStmt overallTy g.unit_ty + UnifyTypes cenv env mStmt overallTy.Commit g.unit_ty let fieldTy = rfinfo.FieldType // Always allow subsumption on assignment to fields let e2', tpenv = TcExprFlex cenv true false fieldTy env tpenv e2 @@ -8284,7 +8453,7 @@ and TcLookupThen cenv overallTy env tpenv mObjExpr objExpr objExprTy longId dela | DelayedSet(e2, mStmt) :: otherDelayed -> if not (isNil otherDelayed) then error(Error(FSComp.SR.tcInvalidAssignment(), mStmt)) // Instance property setter - UnifyTypes cenv env mStmt overallTy cenv.g.unit_ty + UnifyTypes cenv env mStmt overallTy.Commit cenv.g.unit_ty let meths = SettersOfPropInfos pinfos if meths.IsEmpty then let meths = pinfos |> GettersOfPropInfos @@ -8317,7 +8486,7 @@ and TcLookupThen cenv overallTy env tpenv mObjExpr objExpr objExprTy longId dela // Mutable value set: 'v <- e' if not (isNil otherDelayed) then error(Error(FSComp.SR.tcInvalidAssignment(), mItem)) CheckRecdFieldMutation mItem env.DisplayEnv rfinfo - UnifyTypes cenv env mStmt overallTy cenv.g.unit_ty + UnifyTypes cenv env mStmt overallTy.Commit cenv.g.unit_ty // Always allow subsumption on assignment to fields let e2', tpenv = TcExprFlex cenv true false fieldTy env tpenv e2 BuildRecdFieldSet cenv.g mStmt objExpr rfinfo e2', tpenv @@ -8348,7 +8517,7 @@ and TcLookupThen cenv overallTy env tpenv mObjExpr objExpr objExprTy longId dela match delayed with // Set instance IL field | DelayedSet(e2, mStmt) :: _delayed' -> - UnifyTypes cenv env mStmt overallTy cenv.g.unit_ty + UnifyTypes cenv env mStmt overallTy.Commit cenv.g.unit_ty // Always allow subsumption on assignment to fields let e2', tpenv = TcExprFlex cenv true false exprty env tpenv e2 let expr = BuildILFieldSet cenv.g mStmt objExpr finfo e2' @@ -8417,8 +8586,9 @@ and TcEventValueThen cenv overallTy env tpenv mItem mExprAndItem objDetails (ein and TcMethodApplicationThen cenv env - overallTy // The type of the overall expression including "delayed". The method "application" may actually be a use of a member as - // a first-class function value, when this would be a function type. + // The type of the overall expression including "delayed". The method "application" may actually be a use of a member as + // a first-class function value, when this would be a function type. + (overallTy: OverallTy) objTyOpt // methodType tpenv callerTyArgs // The return type of the overall expression including "delayed" @@ -8442,7 +8612,7 @@ and TcMethodApplicationThen // Work out if we know anything about the return type of the overall expression. If there are any delayed // lookups then we don't know anything. - let exprTy = if isNil delayed then overallTy else NewInferenceType () + let exprTy = if isNil delayed then overallTy else MustEqual (NewInferenceType ()) // Call the helper below to do the real checking let (expr, attributeAssignedNamedItems, delayed), tpenv = @@ -8481,7 +8651,7 @@ and TcMethodApplication mMethExpr // range of the entire method expression mItem methodName - (objTyOpt: TType option) + (objTyOpt: TType option) ad mut isProp @@ -8489,7 +8659,7 @@ and TcMethodApplication afterResolution isSuperInit curriedCallerArgs - exprTy + (exprTy: OverallTy) delayed = @@ -8507,7 +8677,7 @@ and TcMethodApplication let curriedCallerArgs, exprTy, delayed = match calledMeths with | [calledMeth] when not isProp && calledMeth.NumArgs.Length > 1 -> - [], NewInferenceType (), [ for x in curriedCallerArgs -> DelayedApp(ExprAtomicFlag.NonAtomic, x, x.Range) ] @ delayed + [], MustEqual (NewInferenceType ()), [ for x in curriedCallerArgs -> DelayedApp(ExprAtomicFlag.NonAtomic, x, x.Range) ] @ delayed | _ when not isProp && calledMeths |> List.exists (fun calledMeth -> calledMeth.NumArgs.Length > 1) -> // This condition should only apply when multiple conflicting curried extension members are brought into scope error(Error(FSComp.SR.tcOverloadsCannotHaveCurriedArguments(), mMethExpr)) @@ -8581,9 +8751,9 @@ and TcMethodApplication curriedCalledArgs.Head |> List.forall isSimpleFormalArg) -> // The call lambda has function type - let exprTy = mkFunTy (NewInferenceType ()) exprTy + let exprTy = mkFunTy (NewInferenceType ()) exprTy.Commit - (None, Some unnamedCurriedCallerArgs.Head.Head, exprTy) + (None, Some unnamedCurriedCallerArgs.Head.Head, MustEqual exprTy) | _ -> let unnamedCurriedCallerArgs = unnamedCurriedCallerArgs |> List.mapSquared MakeUnnamedCallerArgInfo @@ -8640,10 +8810,10 @@ and TcMethodApplication // method will take. Optional and out args are _not_ included, which means they will be resolved // to their default values (for optionals) and be part of the return tuple (for out args). | None, [calledMeth] -> - let curriedArgTys, returnTy = UnifyMatchingSimpleArgumentTypes exprTy calledMeth + let curriedArgTys, returnTy = UnifyMatchingSimpleArgumentTypes exprTy.Commit calledMeth let unnamedCurriedCallerArgs = curriedArgTys |> List.mapSquared (fun ty -> CallerArg(ty, mMethExpr, false, dummyExpr)) let namedCurriedCallerArgs = unnamedCurriedCallerArgs |> List.map (fun _ -> []) - unnamedCurriedCallerArgs, namedCurriedCallerArgs, returnTy + unnamedCurriedCallerArgs, namedCurriedCallerArgs, MustEqual returnTy // "type directed" rule for first-class uses of ambiguous methods. // By context we know a type for the input argument. If it's a tuple @@ -8651,7 +8821,7 @@ and TcMethodApplication // type we assume the number of arguments is just "1". | None, _ -> - let domainTy, returnTy = UnifyFunctionType None cenv denv mMethExpr exprTy + let domainTy, returnTy = UnifyFunctionType None cenv denv mMethExpr exprTy.Commit let argTys = if isUnitTy cenv.g domainTy then [] else tryDestRefTupleTy cenv.g domainTy // Only apply this rule if a candidate method exists with this number of arguments let argTys = @@ -8661,7 +8831,7 @@ and TcMethodApplication [domainTy] let unnamedCurriedCallerArgs = [argTys |> List.map (fun ty -> CallerArg(ty, mMethExpr, false, dummyExpr)) ] let namedCurriedCallerArgs = unnamedCurriedCallerArgs |> List.map (fun _ -> []) - unnamedCurriedCallerArgs, namedCurriedCallerArgs, returnTy + unnamedCurriedCallerArgs, namedCurriedCallerArgs, MustEqual returnTy | Some (unnamedCurriedCallerArgs, namedCurriedCallerArgs), _ -> let unnamedCurriedCallerArgs = unnamedCurriedCallerArgs |> List.mapSquared (fun (argExpr, argTy, mArg) -> CallerArg(argTy, mArg, false, argExpr)) @@ -8710,9 +8880,10 @@ and TcMethodApplication // method will take. Optional and out args are _not_ included, which means they will be resolved // to their default values (for optionals) and be part of the return tuple (for out args). | [calledMeth] -> - UnifyMatchingSimpleArgumentTypes exprTy calledMeth + let curriedArgTys, returnTy = UnifyMatchingSimpleArgumentTypes exprTy.Commit calledMeth + curriedArgTys, MustEqual returnTy | _ -> - let domainTy, returnTy = UnifyFunctionType None cenv denv mMethExpr exprTy + let domainTy, returnTy = UnifyFunctionType None cenv denv mMethExpr exprTy.Commit let argTys = if isUnitTy cenv.g domainTy then [] else tryDestRefTupleTy cenv.g domainTy // Only apply this rule if a candidate method exists with this number of arguments let argTys = @@ -8720,7 +8891,7 @@ and TcMethodApplication argTys else [domainTy] - [argTys], returnTy + [argTys], MustEqual returnTy let lambdaVarsAndExprs = curriedArgTys |> List.mapiSquared (fun i j ty -> mkCompGenLocal mMethExpr ("arg"+string i+string j) ty) let unnamedCurriedCallerArgs = lambdaVarsAndExprs |> List.mapSquared (fun (_, e) -> CallerArg(tyOfExpr cenv.g e, e.Range, false, e)) @@ -8738,7 +8909,7 @@ and TcMethodApplication let lambdaPropagationInfo = if preArgumentTypeCheckingCalledMethGroup.Length > 1 then [| for meth in preArgumentTypeCheckingCalledMethGroup do - match ExamineMethodForLambdaPropagation meth with + match ExamineMethodForLambdaPropagation meth ad with | Some (unnamedInfo, namedInfo) -> let calledObjArgTys = meth.CalledObjArgTys mMethExpr if (calledObjArgTys, callerObjArgTys) ||> Seq.forall2 (fun calledTy callerTy -> AddCxTypeMustSubsumeTypeMatchingOnlyUndoIfFailed denv cenv.css mMethExpr calledTy callerTy) then @@ -8824,7 +8995,6 @@ and TcMethodApplication | AfterResolution.RecordResolution(_, _, _, onFailure), None -> onFailure() - // Raise the errors from the constraint solving RaiseOperationResult errors match result with @@ -8873,7 +9043,8 @@ and TcMethodApplication /// STEP 5. Build the argument list. Adjust for optional arguments, byref arguments and coercions. let objArgPreBinder, objArgs, allArgsPreBinders, allArgs, allArgsCoerced, optArgPreBinder, paramArrayPreBinders, outArgExprs, outArgTmpBinds = - AdjustCallerArgs TcFieldInit env.eCallerMemberName cenv.infoReader ad finalCalledMeth objArgs lambdaVars mItem mMethExpr + let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g + AdjustCallerArgs tcVal TcFieldInit env.eCallerMemberName cenv.infoReader ad finalCalledMeth objArgs lambdaVars mItem mMethExpr // Record the resolution of the named argument for the Language Service allArgs |> List.iter (fun assignedArg -> @@ -8891,13 +9062,13 @@ and TcMethodApplication BuildPossiblyConditionalMethodCall cenv env mut mMethExpr isProp finalCalledMethInfo isSuperInit finalCalledMethInst objArgs allArgsCoerced // Handle byref returns - let callExpr1 = + let callExpr1, exprty = // byref-typed returns get implicitly dereferenced let vty = tyOfExpr cenv.g callExpr0 if isByrefTy cenv.g vty then - mkDerefAddrExpr mMethExpr callExpr0 mMethExpr vty + mkDerefAddrExpr mMethExpr callExpr0 mMethExpr vty, destByrefTy cenv.g vty else - callExpr0 + callExpr0, exprty // Bind "out" parameters as part of the result tuple let callExpr2, exprty = @@ -8913,9 +9084,12 @@ and TcMethodApplication let expr = mkLetsBind mMethExpr outArgTmpBinds expr expr, tyOfExpr cenv.g expr + // Subsumption or conversion to return type + let callExpr2b = TcAdjustExprForTypeDirectedConversions cenv returnTy exprty env mMethExpr callExpr2 + // Handle post-hoc property assignments let setterExprPrebinders, callExpr3 = - let expr = callExpr2 + let expr = callExpr2b if isCheckingAttributeCall then [], expr elif isNil finalAssignedItemSetters then @@ -8952,7 +9126,7 @@ and TcMethodApplication | Some synArgExpr -> match lambdaVars with | Some [lambdaVars] -> - let argExpr, tpenv = TcExpr cenv (mkRefTupledVarsTy cenv.g lambdaVars) env tpenv synArgExpr + let argExpr, tpenv = TcExpr cenv (MustEqual (mkRefTupledVarsTy cenv.g lambdaVars)) env tpenv synArgExpr mkApps cenv.g ((expr, tyOfExpr cenv.g expr), [], [argExpr], mMethExpr), tpenv | _ -> error(InternalError("unreachable - expected some lambda vars for a tuple mismatch", mItem)) @@ -8980,7 +9154,8 @@ and TcSetterArgExpr cenv env denv objExpr ad (AssignedItemSetter(id, setter, Cal | AssignedPropSetter (pinfo, pminfo, pminst) -> MethInfoChecks cenv.g cenv.amap true None [objExpr] ad m pminfo let calledArgTy = List.head (List.head (pminfo.GetParamTypes(cenv.amap, m, pminst))) - let argExprPrebinder, argExpr = AdjustCallerArgExprForCoercions cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr + let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g + let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExpr tcVal cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr let mut = (if isStructTy cenv.g (tyOfExpr cenv.g objExpr) then DefinitelyMutates else PossiblyMutates) let action = BuildPossiblyConditionalMethodCall cenv env mut m true pminfo NormalValUse pminst [objExpr] [argExpr] |> fst argExprPrebinder, action, Item.Property (pinfo.PropertyName, [pinfo]) @@ -8989,7 +9164,8 @@ and TcSetterArgExpr cenv env denv objExpr ad (AssignedItemSetter(id, setter, Cal // Get or set instance IL field ILFieldInstanceChecks cenv.g cenv.amap ad m finfo let calledArgTy = finfo.FieldType (cenv.amap, m) - let argExprPrebinder, argExpr = AdjustCallerArgExprForCoercions cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr + let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g + let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExpr tcVal cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr let action = BuildILFieldSet cenv.g m objExpr finfo argExpr argExprPrebinder, action, Item.ILField finfo @@ -8997,7 +9173,8 @@ and TcSetterArgExpr cenv env denv objExpr ad (AssignedItemSetter(id, setter, Cal RecdFieldInstanceChecks cenv.g cenv.amap ad m rfinfo let calledArgTy = rfinfo.FieldType CheckRecdFieldMutation m denv rfinfo - let argExprPrebinder, argExpr = AdjustCallerArgExprForCoercions cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr + let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g + let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExpr tcVal cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr let action = BuildRecdFieldSet cenv.g m objExpr rfinfo argExpr argExprPrebinder, action, Item.RecdField rfinfo @@ -9069,7 +9246,7 @@ and TcMethodArg cenv env (lambdaPropagationInfo, tpenv) (lambdaPropagationInfoFo | _ -> () loop argTy 0 - let e', tpenv = TcExpr cenv argTy env tpenv argExpr + let e', tpenv = TcExprFlex2 cenv argTy env true tpenv argExpr // After we have checked, propagate the info from argument into the overloads that receive it. // @@ -9088,9 +9265,9 @@ and TcMethodArg cenv env (lambdaPropagationInfo, tpenv) (lambdaPropagationInfoFo CallerArg(argTy, mArg, isOpt, e'), (lambdaPropagationInfo, tpenv) /// Typecheck "new Delegate(fun x y z -> ...)" constructs -and TcNewDelegateThen cenv overallTy env tpenv mDelTy mExprAndArg delegateTy arg atomicFlag delayed = +and TcNewDelegateThen cenv (overallTy: OverallTy) env tpenv mDelTy mExprAndArg delegateTy arg atomicFlag delayed = let ad = env.eAccessRights - UnifyTypes cenv env mExprAndArg overallTy delegateTy + UnifyTypes cenv env mExprAndArg overallTy.Commit delegateTy let (SigOfFunctionForDelegate(invokeMethInfo, delArgTys, _, fty)) = GetSigOfFunctionForDelegate cenv.infoReader delegateTy mDelTy ad // We pass isInstance = true here because we're checking the rights to access the "Invoke" method MethInfoChecks cenv.g cenv.amap true None [] env.eAccessRights mExprAndArg invokeMethInfo @@ -9153,10 +9330,10 @@ and TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr expr cont = let envinner = ShrinkContext envinner m body.Range // tailcall TcLinearExprs bodyChecker cenv envinner overallTy tpenv isCompExpr body (fun (x, tpenv) -> - cont (fst (mkf (x, overallTy)), tpenv)) + cont (fst (mkf (x, overallTy.Commit)), tpenv)) | SynExpr.IfThenElse (_, _, synBoolExpr, _, synThenExpr, _, synElseExprOpt, spIfToThen, isRecovery, mIfToThen, m) when not isCompExpr -> - let boolExpr, tpenv = TcExprThatCantBeCtorBody cenv cenv.g.bool_ty env tpenv synBoolExpr + let boolExpr, tpenv = TcExprThatCantBeCtorBody cenv (MustEqual cenv.g.bool_ty) env tpenv synBoolExpr let thenExpr, tpenv = let env = match env.eContextInfo with @@ -9167,7 +9344,7 @@ and TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr expr cont = | _ -> { env with eContextInfo = ContextInfo.IfExpression synThenExpr.Range } if not isRecovery && Option.isNone synElseExprOpt then - UnifyTypes cenv env m cenv.g.unit_ty overallTy + UnifyTypes cenv env m cenv.g.unit_ty overallTy.Commit TcExprThatCanBeCtorBody cenv overallTy env tpenv synThenExpr @@ -9175,14 +9352,14 @@ and TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr expr cont = | None -> let elseExpr = mkUnit cenv.g mIfToThen let spElse = DebugPointForTarget.No // the fake 'unit' value gets exactly the same range as spIfToThen - let overallExpr = primMkCond spIfToThen DebugPointForTarget.Yes spElse m overallTy boolExpr thenExpr elseExpr + let overallExpr = primMkCond spIfToThen DebugPointForTarget.Yes spElse m overallTy.Commit boolExpr thenExpr elseExpr cont (overallExpr, tpenv) | Some synElseExpr -> let env = { env with eContextInfo = ContextInfo.ElseBranchResult synElseExpr.Range } // tailcall TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr synElseExpr (fun (elseExpr, tpenv) -> - let resExpr = primMkCond spIfToThen DebugPointForTarget.Yes DebugPointForTarget.Yes m overallTy boolExpr thenExpr elseExpr + let resExpr = primMkCond spIfToThen DebugPointForTarget.Yes DebugPointForTarget.Yes m overallTy.Commit boolExpr thenExpr elseExpr cont (resExpr, tpenv)) | _ -> @@ -9191,7 +9368,7 @@ and TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr expr cont = /// Typecheck and compile pattern-matching constructs and TcAndPatternCompileMatchClauses mExpr matchm actionOnFailure cenv inputExprOpt inputTy resultTy env tpenv synClauses = let clauses, tpenv = TcMatchClauses cenv inputTy resultTy env tpenv synClauses - let matchVal, expr = CompilePatternForMatchClauses cenv env mExpr matchm true actionOnFailure inputExprOpt inputTy resultTy clauses + let matchVal, expr = CompilePatternForMatchClauses cenv env mExpr matchm true actionOnFailure inputExprOpt inputTy resultTy.Commit clauses matchVal, expr, tpenv and TcMatchPattern cenv inputTy env tpenv (pat: SynPat, optWhenExpr: SynExpr option) = @@ -9202,17 +9379,18 @@ and TcMatchPattern cenv inputTy env tpenv (pat: SynPat, optWhenExpr: SynExpr opt match optWhenExpr with | Some whenExpr -> let guardEnv = { envinner with eContextInfo = ContextInfo.PatternMatchGuard whenExpr.Range } - let whenExpr', tpenv = TcExpr cenv cenv.g.bool_ty guardEnv tpenv whenExpr + let whenExpr', tpenv = TcExpr cenv (MustEqual cenv.g.bool_ty) guardEnv tpenv whenExpr Some whenExpr', tpenv | None -> None, tpenv patf' (TcPatPhase2Input (values, true)), optWhenExpr', NameMap.range vspecMap, envinner, tpenv -and TcMatchClauses cenv inputTy resultTy env tpenv clauses = +and TcMatchClauses cenv inputTy (resultTy: OverallTy) env tpenv clauses = let mutable first = true let isFirst() = if first then first <- false; true else false List.mapFold (fun clause -> TcMatchClause cenv inputTy resultTy env (isFirst()) clause) tpenv clauses -and TcMatchClause cenv inputTy resultTy env isFirst tpenv (SynMatchClause(pat, optWhenExpr, _, e, patm, spTgt)) = +and TcMatchClause cenv inputTy (resultTy: OverallTy) env isFirst tpenv synMatchClause = + let (SynMatchClause(pat, optWhenExpr, _, e, patm, spTgt)) = synMatchClause let pat', optWhenExpr', vspecs, envinner, tpenv = TcMatchPattern cenv inputTy env tpenv (pat, optWhenExpr) let resultEnv = if isFirst then envinner else { envinner with eContextInfo = ContextInfo.FollowingPatternMatchClause e.Range } let e', tpenv = TcExprThatCanBeCtorBody cenv resultTy resultEnv tpenv e @@ -9501,8 +9679,8 @@ and TcNormalizedBinding declKind (cenv: cenv) env tpenv overallTy safeThisValOpt let (PartialValReprInfo(argInfos, _)) = partialValReprInfo let envinner = { envinner with eLambdaArgInfos = argInfos } - if isCtor then TcExprThatIsCtorBody (safeThisValOpt, safeInitInfo) cenv overallExprTy envinner tpenv rhsExpr - else TcExprThatCantBeCtorBody cenv overallExprTy envinner tpenv rhsExpr) + if isCtor then TcExprThatIsCtorBody (safeThisValOpt, safeInitInfo) cenv (MustEqual overallExprTy) envinner tpenv rhsExpr + else TcExprThatCantBeCtorBody cenv (MustConvertTo (false, overallExprTy)) envinner tpenv rhsExpr) if bkind = SynBindingKind.StandaloneExpression && not cenv.isScript then UnifyUnitType cenv env mBinding overallPatTy rhsExprChecked |> ignore @@ -9543,7 +9721,7 @@ and TcNormalizedBinding declKind (cenv: cenv) env tpenv overallTy safeThisValOpt and TcLiteral cenv overallTy env tpenv (attrs, synLiteralValExpr) = let hasLiteralAttr = HasFSharpAttribute cenv.g cenv.g.attrib_LiteralAttribute attrs if hasLiteralAttr then - let literalValExpr, _ = TcExpr cenv overallTy env tpenv synLiteralValExpr + let literalValExpr, _ = TcExpr cenv (MustEqual overallTy) env tpenv synLiteralValExpr match EvalLiteralExprOrAttribArg cenv.g literalValExpr with | Expr.Const (c, _, ty) -> if c = Const.Zero && isStructTy cenv.g ty then @@ -9692,7 +9870,7 @@ and TcAttributeEx canFail cenv (env: TcEnv) attrTgt attrEx (synAttr: SynAttribut let meths = minfos |> List.map (fun minfo -> minfo, None) let afterResolution = ForNewConstructors cenv.tcSink env tyid.idRange methodName minfos let (expr, attributeAssignedNamedItems, _), _ = - TcMethodApplication true cenv env tpenv None [] mAttr mAttr methodName None ad PossiblyMutates false meths afterResolution NormalValUse [arg] (NewInferenceType ()) [] + TcMethodApplication true cenv env tpenv None [] mAttr mAttr methodName None ad PossiblyMutates false meths afterResolution NormalValUse [arg] (MustEqual ty) [] UnifyTypes cenv env mAttr ty (tyOfExpr cenv.g expr) @@ -10027,12 +10205,7 @@ and ApplyAbstractSlotInference (cenv: cenv) (envinner: TcEnv) (bindingTy, m, syn match dispatchSlotsArityMatch with | meths when methInfosEquivByNameAndSig meths -> meths | [] -> - let details = - slots - |> Seq.map (NicePrint.stringOfMethInfo cenv.infoReader m envinner.DisplayEnv) - |> Seq.map (sprintf "%s %s" Environment.NewLine) - |> String.concat "" - + let details = NicePrint.multiLineStringOfMethInfos cenv.infoReader m envinner.DisplayEnv slots errorR(Error(FSComp.SR.tcOverrideArityMismatch details, memberId.idRange)) [] | _ -> [] // check that method to override is sealed is located at CheckOverridesAreAllUsedOnce (typrelns.fs) diff --git a/src/fsharp/CheckExpressions.fsi b/src/fsharp/CheckExpressions.fsi index 1b29c65a556..bef3163d4ca 100644 --- a/src/fsharp/CheckExpressions.fsi +++ b/src/fsharp/CheckExpressions.fsi @@ -227,11 +227,11 @@ type TcFileState = isInternalTestSpanStackReferring: bool // forward call - TcSequenceExpressionEntry: TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> bool * bool ref * SynExpr -> range -> Expr * UnscopedTyparEnv + TcSequenceExpressionEntry: TcFileState -> TcEnv -> OverallTy -> UnscopedTyparEnv -> bool * bool ref * SynExpr -> range -> Expr * UnscopedTyparEnv // forward call - TcArrayOrListSequenceExpression: TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> bool * SynExpr -> range -> Expr * UnscopedTyparEnv + TcArrayOrListSequenceExpression: TcFileState -> TcEnv -> OverallTy -> UnscopedTyparEnv -> bool * SynExpr -> range -> Expr * UnscopedTyparEnv // forward call - TcComputationExpression: TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> range * Expr * TType * SynExpr -> Expr * UnscopedTyparEnv + TcComputationExpression: TcFileState -> TcEnv -> OverallTy -> UnscopedTyparEnv -> range * Expr * TType * SynExpr -> Expr * UnscopedTyparEnv } static member Create: g: TcGlobals * @@ -246,11 +246,11 @@ type TcFileState = tcVal: TcValF * isInternalTestSpanStackReferring: bool * // forward call to CheckComputationExpressions.fs - tcSequenceExpressionEntry: (TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> bool * bool ref * SynExpr -> range -> Expr * UnscopedTyparEnv) * + tcSequenceExpressionEntry: (TcFileState -> TcEnv -> OverallTy -> UnscopedTyparEnv -> bool * bool ref * SynExpr -> range -> Expr * UnscopedTyparEnv) * // forward call to CheckComputationExpressions.fs - tcArrayOrListSequenceExpression: (TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> bool * SynExpr -> range -> Expr * UnscopedTyparEnv) * + tcArrayOrListSequenceExpression: (TcFileState -> TcEnv -> OverallTy -> UnscopedTyparEnv -> bool * SynExpr -> range -> Expr * UnscopedTyparEnv) * // forward call to CheckComputationExpressions.fs - tcComputationExpression: (TcFileState -> TcEnv -> TType -> UnscopedTyparEnv -> range * Expr * TType * SynExpr -> Expr * UnscopedTyparEnv) + tcComputationExpression: (TcFileState -> TcEnv -> OverallTy -> UnscopedTyparEnv -> range * Expr * TType * SynExpr -> Expr * UnscopedTyparEnv) -> TcFileState /// Represents information about the module or type in which a member or value is declared. @@ -652,28 +652,33 @@ val TcAttributesCanFail: cenv:TcFileState -> env:TcEnv -> attrTgt:AttributeTarge val TcAttributesWithPossibleTargets: canFail: bool -> cenv: TcFileState -> env: TcEnv -> attrTgt: AttributeTargets -> synAttribs: SynAttribute list -> (AttributeTargets * Attrib) list * bool /// Check a constant value, e.g. a literal -val TcConst: cenv: TcFileState -> ty: TType -> m: range -> env: TcEnv -> c: SynConst -> Const +val TcConst: cenv: TcFileState -> overallTy: TType -> m: range -> env: TcEnv -> c: SynConst -> Const /// Check a syntactic expression and convert it to a typed tree expression -val TcExpr: cenv:TcFileState -> ty:TType -> env:TcEnv -> tpenv:UnscopedTyparEnv -> expr:SynExpr -> Expr * UnscopedTyparEnv +val TcExpr: cenv:TcFileState -> ty:OverallTy -> env:TcEnv -> tpenv:UnscopedTyparEnv -> expr:SynExpr -> Expr * UnscopedTyparEnv /// Check a syntactic expression and convert it to a typed tree expression val TcExprOfUnknownType: cenv:TcFileState -> env:TcEnv -> tpenv:UnscopedTyparEnv -> expr:SynExpr -> Expr * TType * UnscopedTyparEnv /// Check a syntactic expression and convert it to a typed tree expression. Possibly allow for subsumption flexibility /// and insert a coercion if necessary. -val TcExprFlex: cenv:TcFileState -> flex:bool -> compat:bool -> ty:TType -> env:TcEnv -> tpenv:UnscopedTyparEnv -> e:SynExpr -> Expr * UnscopedTyparEnv +val TcExprFlex: cenv:TcFileState -> flex:bool -> compat:bool -> desiredTy:TType -> env:TcEnv -> tpenv:UnscopedTyparEnv -> synExpr:SynExpr -> Expr * UnscopedTyparEnv + +/// Process a leaf construct where the actual type of that construct is already pre-known, +/// and the overall type can be eagerly propagated into the actual type, including pre-calculating +/// any type-directed conversion. +val TcPropagatingExprLeafThenConvert: cenv:TcFileState -> overallTy: OverallTy -> actualTy: TType -> env: TcEnv -> m: range -> f: (unit -> Expr * UnscopedTyparEnv) -> Expr * UnscopedTyparEnv /// Check a syntactic statement and convert it to a typed tree expression. val TcStmtThatCantBeCtorBody: cenv:TcFileState -> env:TcEnv -> tpenv:UnscopedTyparEnv -> expr:SynExpr -> Expr * UnscopedTyparEnv /// Check a syntactic expression and convert it to a typed tree expression -val TcExprUndelayed: cenv:TcFileState -> overallTy:TType -> env:TcEnv -> tpenv:UnscopedTyparEnv -> synExpr:SynExpr -> Expr * UnscopedTyparEnv +val TcExprUndelayed: cenv:TcFileState -> overallTy:OverallTy -> env:TcEnv -> tpenv:UnscopedTyparEnv -> synExpr:SynExpr -> Expr * UnscopedTyparEnv /// Check a linear expression (e.g. a sequence of 'let') in a tail-recursive way /// and convert it to a typed tree expression, using the bodyChecker to check the parts /// that are not linear. -val TcLinearExprs: bodyChecker:(TType -> TcEnv -> UnscopedTyparEnv -> SynExpr -> Expr * UnscopedTyparEnv) -> cenv:TcFileState -> env:TcEnv -> overallTy:TType -> tpenv:UnscopedTyparEnv -> isCompExpr:bool -> expr:SynExpr -> cont:(Expr * UnscopedTyparEnv -> Expr * UnscopedTyparEnv) -> Expr * UnscopedTyparEnv +val TcLinearExprs: bodyChecker:(OverallTy -> TcEnv -> UnscopedTyparEnv -> SynExpr -> Expr * UnscopedTyparEnv) -> cenv:TcFileState -> env:TcEnv -> overallTy:OverallTy -> tpenv:UnscopedTyparEnv -> isCompExpr:bool -> expr:SynExpr -> cont:(Expr * UnscopedTyparEnv -> Expr * UnscopedTyparEnv) -> Expr * UnscopedTyparEnv /// Try to check a syntactic statement and indicate if it's type is not unit without emitting a warning val TryTcStmt: cenv:TcFileState -> env:TcEnv -> tpenv:UnscopedTyparEnv -> synExpr:SynExpr -> bool * Expr * UnscopedTyparEnv diff --git a/src/fsharp/CompilerDiagnostics.fs b/src/fsharp/CompilerDiagnostics.fs index 2006048da01..8ce2fe9e148 100644 --- a/src/fsharp/CompilerDiagnostics.fs +++ b/src/fsharp/CompilerDiagnostics.fs @@ -375,6 +375,9 @@ let warningOn err level specificWarnOn = | 1182 -> false // chkUnusedValue - off by default | 3180 -> false // abImplicitHeapAllocation - off by default | 3517 -> false // optFailedToInlineSuggestedValue - off by default + | 3388 -> false // tcSubsumptionImplicitConversionUsed - off by default + | 3389 -> false // tcBuiltInImplicitConversionUsed - off by default + | 3390 -> false // tcImplicitConversionUsedForMethodArg - off by default | _ -> level >= GetWarningLevel err let SplitRelatedDiagnostics(err: PhasedDiagnostic) : PhasedDiagnostic * PhasedDiagnostic list = diff --git a/src/fsharp/ConstraintSolver.fs b/src/fsharp/ConstraintSolver.fs index ba4f4469f90..74336feb445 100644 --- a/src/fsharp/ConstraintSolver.fs +++ b/src/fsharp/ConstraintSolver.fs @@ -207,6 +207,19 @@ type OverloadResolutionFailure = * candidates: OverloadInformation list // methodNames may be different (with operators?), this is refactored from original logic to assemble overload failure message * cx: TraitConstraintInfo option +type OverallTy = + /// Each branch of the expression must have the type indicated + | MustEqual of TType + + /// Each branch of the expression must convert to the type indicated + | MustConvertTo of isMethodArg: bool * ty: TType + + /// Represents a point where no subsumption/widening is possible + member x.Commit = + match x with + | MustEqual ty -> ty + | MustConvertTo (_, ty) -> ty + exception ConstraintSolverTupleDiffLengths of displayEnv: DisplayEnv * TType list * TType list * range * range exception ConstraintSolverInfiniteTypes of displayEnv: DisplayEnv * contextInfo: ContextInfo * TType * TType * range * range @@ -474,7 +487,7 @@ let FilterEachThenUndo f meths = trace.Undo() match CheckNoErrorsAndGetWarnings res with | None -> None - | Some warns -> Some (calledMeth, warns, trace)) + | Some (warns, res) -> Some (calledMeth, warns, trace, res)) let ShowAccessDomain ad = match ad with @@ -1563,7 +1576,7 @@ and SolveMemberConstraint (csenv: ConstraintSolverEnv) ignoreUnresolvedOverload let methOverloadResult, errors = trace.CollectThenUndoOrCommit (fun (a, _) -> Option.isSome a) - (fun trace -> ResolveOverloading csenv (WithTrace trace) nm ndeep (Some traitInfo) CallerArgs.Empty AccessibleFromEverywhere calledMethGroup false (Some rty)) + (fun trace -> ResolveOverloading csenv (WithTrace trace) nm ndeep (Some traitInfo) CallerArgs.Empty AccessibleFromEverywhere calledMethGroup false (Some (MustEqual rty))) match anonRecdPropSearch, recdPropSearch, methOverloadResult with | Some (anonInfo, tinst, i), None, None -> @@ -2238,11 +2251,12 @@ and CanMemberSigsMatchUpToCheck (csenv: ConstraintSolverEnv) permitOptArgs // are we allowed to supply optional and/or "param" arguments? alwaysCheckReturn // always check the return type? - unifyTypes // used to equate the formal method instantiation with the actual method instantiation for a generic method, and the return types - subsumeTypes // used to compare the "obj" type - (subsumeArg: CalledArg -> CallerArg<_> -> OperationResult) // used to compare the arguments for compatibility - reqdRetTyOpt - (calledMeth: CalledMeth<_>): ImperativeOperationResult = + (unifyTypes: TType -> TType -> OperationResult) // used to equate the formal method instantiation with the actual method instantiation for a generic method, and the return types + (subsumeTypes: TType -> TType -> OperationResult) // used to compare the "obj" type + (subsumeOrConvertTypes: TType -> TType -> OperationResult) // used to convert the "return" for MustConvertTo + (subsumeOrConvertArg: CalledArg -> CallerArg<_> -> OperationResult) // used to convert the arguments + (reqdRetTyOpt: OverallTy option) + (calledMeth: CalledMeth<_>): OperationResult = trackErrors { let g = csenv.g let amap = csenv.amap @@ -2260,41 +2274,60 @@ and CanMemberSigsMatchUpToCheck if minst.Length <> uminst.Length then return! ErrorD(Error(FSComp.SR.csTypeInstantiationLengthMismatch(), m)) else - do! Iterate2D unifyTypes minst uminst - if not (permitOptArgs || isNil unnamedCalledOptArgs) then - return! ErrorD(Error(FSComp.SR.csOptionalArgumentNotPermittedHere(), m)) - else - let calledObjArgTys = calledMeth.CalledObjArgTys(m) + let! usesTDC1 = MapCombineTDC2D unifyTypes minst uminst + let! usesTDC2 = + trackErrors { + if not (permitOptArgs || isNil unnamedCalledOptArgs) then + return! ErrorD(Error(FSComp.SR.csOptionalArgumentNotPermittedHere(), m)) + else + let calledObjArgTys = calledMeth.CalledObjArgTys(m) - // Check all the argument types. + // Check all the argument types. - if calledObjArgTys.Length <> callerObjArgTys.Length then - if calledObjArgTys.Length <> 0 then - return! ErrorD(Error (FSComp.SR.csMemberIsNotStatic(minfo.LogicalName), m)) + if calledObjArgTys.Length <> callerObjArgTys.Length then + if calledObjArgTys.Length <> 0 then + return! ErrorD(Error (FSComp.SR.csMemberIsNotStatic(minfo.LogicalName), m)) + else + return! ErrorD(Error (FSComp.SR.csMemberIsNotInstance(minfo.LogicalName), m)) + else + return! MapCombineTDC2D subsumeTypes calledObjArgTys callerObjArgTys + } + + let! usesTDC3 = + calledMeth.ArgSets |> MapCombineTDCD (fun argSet -> trackErrors { + if argSet.UnnamedCalledArgs.Length <> argSet.UnnamedCallerArgs.Length then + return! ErrorD(Error(FSComp.SR.csArgumentLengthMismatch(), m)) else - return! ErrorD(Error (FSComp.SR.csMemberIsNotInstance(minfo.LogicalName), m)) - else - do! Iterate2D subsumeTypes calledObjArgTys callerObjArgTys - for argSet in calledMeth.ArgSets do - if argSet.UnnamedCalledArgs.Length <> argSet.UnnamedCallerArgs.Length then - return! ErrorD(Error(FSComp.SR.csArgumentLengthMismatch(), m)) - else - do! Iterate2D subsumeArg argSet.UnnamedCalledArgs argSet.UnnamedCallerArgs - match calledMeth.ParamArrayCalledArgOpt with - | Some calledArg -> - if isArray1DTy g calledArg.CalledArgumentType then - let paramArrayElemTy = destArrayTy g calledArg.CalledArgumentType - let reflArgInfo = calledArg.ReflArgInfo // propagate the reflected-arg info to each param array argument - match calledMeth.ParamArrayCallerArgs with - | Some args -> - for callerArg in args do - do! subsumeArg (CalledArg((0, 0), false, NotOptional, NoCallerInfo, false, false, None, reflArgInfo, paramArrayElemTy)) callerArg - | _ -> () - | _ -> () - for argSet in calledMeth.ArgSets do - for arg in argSet.AssignedNamedArgs do - do! subsumeArg arg.CalledArg arg.CallerArg - for AssignedItemSetter(_, item, caller) in assignedItemSetters do + return! MapCombineTDC2D subsumeOrConvertArg argSet.UnnamedCalledArgs argSet.UnnamedCallerArgs + }) + + let! usesTDC4 = + match calledMeth.ParamArrayCalledArgOpt with + | Some calledArg -> + if isArray1DTy g calledArg.CalledArgumentType then + let paramArrayElemTy = destArrayTy g calledArg.CalledArgumentType + let reflArgInfo = calledArg.ReflArgInfo // propagate the reflected-arg info to each param array argument + match calledMeth.ParamArrayCallerArgs with + | Some args -> + args |> MapCombineTDCD (fun callerArg -> + subsumeOrConvertArg (CalledArg((0, 0), false, NotOptional, NoCallerInfo, false, false, None, reflArgInfo, paramArrayElemTy)) callerArg + ) + + + | _ -> ResultD TypeDirectedConversionUsed.No + else + ResultD TypeDirectedConversionUsed.No + | _ -> ResultD TypeDirectedConversionUsed.No + + let! usesTDC5 = + calledMeth.ArgSets |> MapCombineTDCD (fun argSet -> + argSet.AssignedNamedArgs |> MapCombineTDCD (fun arg -> + subsumeOrConvertArg arg.CalledArg arg.CallerArg + ) + ) + + let! usesTDC6 = + assignedItemSetters |> MapCombineTDCD (fun (AssignedItemSetter(_, item, caller)) -> let name, calledArgTy = match item with | AssignedPropSetter(_, pminfo, pminst) -> @@ -2310,17 +2343,26 @@ and CanMemberSigsMatchUpToCheck let calledArgTy = rfinfo.FieldType rfinfo.Name, calledArgTy - do! subsumeArg (CalledArg((-1, 0), false, NotOptional, NoCallerInfo, false, false, Some (mkSynId m name), ReflectedArgInfo.None, calledArgTy)) caller - // - Always take the return type into account for + subsumeOrConvertArg (CalledArg((-1, 0), false, NotOptional, NoCallerInfo, false, false, Some (mkSynId m name), ReflectedArgInfo.None, calledArgTy)) caller + ) + + // - Always take the return type into account for resolving overloading of // -- op_Explicit, op_Implicit // -- methods using tupling of unfilled out args // - Never take into account return type information for constructors - match reqdRetTyOpt with - | Some _ when (minfo.IsConstructor || not alwaysCheckReturn && isNil unnamedCalledOutArgs) -> () - | Some reqdRetTy -> - let methodRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling - return! unifyTypes reqdRetTy methodRetTy - | _ -> () + let! usesTDC7 = + match reqdRetTyOpt with + | Some _ when ( (* minfo.IsConstructor || *) not alwaysCheckReturn && isNil unnamedCalledOutArgs) -> + ResultD TypeDirectedConversionUsed.No + | Some (MustConvertTo(_, reqdTy)) when g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions -> + let methodRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling + subsumeOrConvertTypes reqdTy methodRetTy + | Some reqdRetTy -> + let methodRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling + unifyTypes reqdRetTy.Commit methodRetTy + | _ -> + ResultD TypeDirectedConversionUsed.No + return Array.reduce TypeDirectedConversionUsed.Combine [| usesTDC1; usesTDC2; usesTDC3; usesTDC4; usesTDC5; usesTDC6; usesTDC7 |] } // Assert a subtype constraint, and wrap an ErrorsFromAddingSubsumptionConstraint error around any failure @@ -2344,7 +2386,7 @@ and private SolveTypeSubsumesTypeWithWrappedContextualReport (csenv: ConstraintS | _ -> ErrorD (wrapper (ErrorsFromAddingSubsumptionConstraint(csenv.g, csenv.DisplayEnv, ty1, ty2, res, csenv.eContextInfo, m)))) and private SolveTypeSubsumesTypeWithReport (csenv: ConstraintSolverEnv) ndeep m trace cxsln ty1 ty2 = - SolveTypeSubsumesTypeWithWrappedContextualReport csenv ndeep m trace cxsln ty1 ty2 id + SolveTypeSubsumesTypeWithWrappedContextualReport csenv ndeep m trace cxsln ty1 ty2 id // ty1: actual // ty2: expected @@ -2355,6 +2397,7 @@ and private SolveTypeEqualsTypeWithReport (csenv: ConstraintSolverEnv) ndeep m and ArgsMustSubsumeOrConvert (csenv: ConstraintSolverEnv) + ad ndeep trace cxsln @@ -2365,29 +2408,95 @@ and ArgsMustSubsumeOrConvert let g = csenv.g let m = callerArg.Range - let calledArgTy = AdjustCalledArgType csenv.InfoReader isConstraint enforceNullableOptionalsKnownTypes calledArg callerArg + let calledArgTy, usesTDC, eqn = AdjustCalledArgType csenv.InfoReader ad isConstraint enforceNullableOptionalsKnownTypes calledArg callerArg + match eqn with + | Some (ty1, ty2, msg) -> + do! SolveTypeEqualsTypeWithReport csenv ndeep m trace cxsln ty1 ty2 + msg csenv.DisplayEnv + | None -> () + match usesTDC with + | TypeDirectedConversionUsed.Yes warn -> do! WarnD(warn csenv.DisplayEnv) + | TypeDirectedConversionUsed.No -> () do! SolveTypeSubsumesTypeWithReport csenv ndeep m trace cxsln calledArgTy callerArg.CallerArgumentType if calledArg.IsParamArray && isArray1DTy g calledArgTy && not (isArray1DTy g callerArg.CallerArgumentType) then return! ErrorD(Error(FSComp.SR.csMethodExpectsParams(), m)) - else () + else + return usesTDC } -and MustUnify csenv ndeep trace cxsln ty1 ty2 = - SolveTypeEqualsTypeWithReport csenv ndeep csenv.m trace cxsln ty1 ty2 +// This is a slight variation on ArgsMustSubsumeOrConvert that adds contextual error report to the +// subsumption check. The two could likely be combines. +and ArgsMustSubsumeOrConvertWithContextualReport + (csenv: ConstraintSolverEnv) + ad + ndeep + trace + cxsln + isConstraint + calledMeth + calledArg + (callerArg: CallerArg) = + trackErrors { + let callerArgTy = callerArg.CallerArgumentType + let m = callerArg.Range + let calledArgTy, usesTDC, eqn = AdjustCalledArgType csenv.InfoReader ad isConstraint true calledArg callerArg + match eqn with + | Some (ty1, ty2, msg) -> + do! SolveTypeEqualsType csenv ndeep m trace cxsln ty1 ty2 + msg csenv.DisplayEnv + | None -> () + match usesTDC with + | TypeDirectedConversionUsed.Yes warn -> do! WarnD(warn csenv.DisplayEnv) + | TypeDirectedConversionUsed.No -> () + do! SolveTypeSubsumesTypeWithWrappedContextualReport csenv ndeep m trace cxsln calledArgTy callerArgTy (fun e -> ArgDoesNotMatchError(e :?> _, calledMeth, calledArg, callerArg)) + return usesTDC + } -and MustUnifyInsideUndo csenv ndeep trace cxsln ty1 ty2 = - SolveTypeEqualsTypeWithReport csenv ndeep csenv.m (WithTrace trace) cxsln ty1 ty2 +and TypesEquiv csenv ndeep trace cxsln ty1 ty2 = + trackErrors { + do! SolveTypeEqualsTypeWithReport csenv ndeep csenv.m trace cxsln ty1 ty2 + return TypeDirectedConversionUsed.No + } -and ArgsMustSubsumeOrConvertInsideUndo (csenv: ConstraintSolverEnv) ndeep trace cxsln isConstraint calledMeth calledArg (CallerArg(callerArgTy, m, _, _) as callerArg) = - let calledArgTy = AdjustCalledArgType csenv.InfoReader isConstraint true calledArg callerArg - SolveTypeSubsumesTypeWithWrappedContextualReport csenv ndeep m (WithTrace trace) cxsln calledArgTy callerArgTy (fun e -> ArgDoesNotMatchError(e :?> _, calledMeth, calledArg, callerArg)) +and TypesMustSubsume (csenv: ConstraintSolverEnv) ndeep trace cxsln m calledArgTy callerArgTy = + trackErrors { + do! SolveTypeSubsumesTypeWithReport csenv ndeep m trace cxsln calledArgTy callerArgTy + return TypeDirectedConversionUsed.No + } -and TypesMustSubsumeOrConvertInsideUndo (csenv: ConstraintSolverEnv) ndeep trace cxsln m calledArgTy callerArgTy = - SolveTypeSubsumesTypeWithReport csenv ndeep m trace cxsln calledArgTy callerArgTy +and ReturnTypesMustSubsumeOrConvert (csenv: ConstraintSolverEnv) ad ndeep trace cxsln isConstraint m reqdTy actualTy = + trackErrors { + let reqdTy, usesTDC, eqn = AdjustRequiredTypeForTypeDirectedConversions csenv.InfoReader ad false isConstraint reqdTy actualTy m + match eqn with + | Some (ty1, ty2, msg) -> + do! SolveTypeEqualsType csenv ndeep m trace cxsln ty1 ty2 + msg csenv.DisplayEnv + | None -> () + match usesTDC with + | TypeDirectedConversionUsed.Yes warn -> do! WarnD(warn csenv.DisplayEnv) + | TypeDirectedConversionUsed.No -> () + do! SolveTypeSubsumesTypeWithReport csenv ndeep m trace cxsln reqdTy actualTy + return usesTDC + } -and ArgsEquivInsideUndo (csenv: ConstraintSolverEnv) isConstraint calledArg (CallerArg(callerArgTy, m, _, _) as callerArg) = - let calledArgTy = AdjustCalledArgType csenv.InfoReader isConstraint true calledArg callerArg - if typeEquiv csenv.g calledArgTy callerArgTy then CompleteD else ErrorD(Error(FSComp.SR.csArgumentTypesDoNotMatch(), m)) +and ArgsEquivOrConvert (csenv: ConstraintSolverEnv) ad ndeep trace cxsln isConstraint calledArg (callerArg: CallerArg<_>) = + trackErrors { + let callerArgTy = callerArg.CallerArgumentType + let m = callerArg.Range + let calledArgTy, usesTDC, eqn = AdjustCalledArgType csenv.InfoReader ad isConstraint true calledArg callerArg + match eqn with + | Some (ty1, ty2, msg) -> + do! SolveTypeEqualsType csenv ndeep m trace cxsln ty1 ty2 + msg csenv.DisplayEnv + | None -> () + match usesTDC with + | TypeDirectedConversionUsed.Yes warn -> do! WarnD(warn csenv.DisplayEnv) + | TypeDirectedConversionUsed.No -> () + if not (typeEquiv csenv.g calledArgTy callerArgTy) then + return! ErrorD(Error(FSComp.SR.csArgumentTypesDoNotMatch(), m)) + else + return usesTDC + } and ReportNoCandidatesError (csenv: ConstraintSolverEnv) (nUnnamedCallerArgs, nNamedCallerArgs) methodName ad (calledMethGroup: CalledMeth<_> list) isSequential = @@ -2523,7 +2632,8 @@ and ResolveOverloading ad // The access domain of the caller, e.g. a module, type etc. calledMethGroup // The set of methods being called permitOptArgs // Can we supply optional arguments? - reqdRetTyOpt // The expected return type, if known + (reqdRetTyOpt: OverallTy option) // The expected return type, if known + : CalledMeth option * OperationResult = let g = csenv.g let infoReader = csenv.InfoReader @@ -2554,35 +2664,41 @@ and ResolveOverloading // Exact match rule. // // See what candidates we have based on current inferred type information - // and _exact_ matches of argument types. - match candidates |> FilterEachThenUndo (fun newTrace calledMeth -> + // and exact matches of argument types. + let exactMatchCandidates = + candidates |> FilterEachThenUndo (fun newTrace calledMeth -> let cxsln = Option.map (fun traitInfo -> (traitInfo, MemberConstraintSolutionOfMethInfo csenv.SolverState m calledMeth.Method calledMeth.CalledTyArgs)) cx CanMemberSigsMatchUpToCheck csenv permitOptArgs alwaysCheckReturn - (MustUnifyInsideUndo csenv ndeep newTrace cxsln) - (TypesMustSubsumeOrConvertInsideUndo csenv ndeep (WithTrace newTrace) cxsln m) - (ArgsEquivInsideUndo csenv cx.IsSome) + (TypesEquiv csenv ndeep (WithTrace newTrace) cxsln) // instantiations equivalent + (TypesMustSubsume csenv ndeep (WithTrace newTrace) cxsln m) // obj can subsume + (ReturnTypesMustSubsumeOrConvert csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome m) // return can subsume or convert + (ArgsEquivOrConvert csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome) // args exact reqdRetTyOpt - calledMeth) with - | [(calledMeth, warns, _)] -> - Some calledMeth, OkResult (warns, ()), NoTrace // Can't re-play the trace since ArgsEquivInsideUndo was used + calledMeth) + + match exactMatchCandidates with + | [(calledMeth, warns, _, _usesTDC)] -> + Some calledMeth, OkResult (warns, ()), NoTrace | _ -> // Now determine the applicable methods. // Subsumption on arguments is allowed. - let applicable = candidates |> FilterEachThenUndo (fun newTrace candidate -> - let cxsln = Option.map (fun traitInfo -> (traitInfo, MemberConstraintSolutionOfMethInfo csenv.SolverState m candidate.Method candidate.CalledTyArgs)) cx - CanMemberSigsMatchUpToCheck - csenv - permitOptArgs - alwaysCheckReturn - (MustUnifyInsideUndo csenv ndeep newTrace cxsln) - (TypesMustSubsumeOrConvertInsideUndo csenv ndeep (WithTrace newTrace) cxsln m) - (ArgsMustSubsumeOrConvertInsideUndo csenv ndeep newTrace cxsln cx.IsSome candidate) - reqdRetTyOpt - candidate) + let applicable = + candidates |> FilterEachThenUndo (fun newTrace candidate -> + let cxsln = Option.map (fun traitInfo -> (traitInfo, MemberConstraintSolutionOfMethInfo csenv.SolverState m candidate.Method candidate.CalledTyArgs)) cx + CanMemberSigsMatchUpToCheck + csenv + permitOptArgs + alwaysCheckReturn + (TypesEquiv csenv ndeep (WithTrace newTrace) cxsln) // instantiations equivalent + (TypesMustSubsume csenv ndeep (WithTrace newTrace) cxsln m) // obj can subsume + (ReturnTypesMustSubsumeOrConvert csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome m) // return can subsume or convert + (ArgsMustSubsumeOrConvertWithContextualReport csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome candidate) // args can subsume + reqdRetTyOpt + candidate) let failOverloading overloadResolutionFailure = // Try to extract information to give better error for ambiguous op_Explicit and op_Implicit @@ -2597,7 +2713,7 @@ and ResolveOverloading match convOpData with | Some (fromTy, toTy) -> - UnresolvedConversionOperator (denv, fromTy, toTy, m) + UnresolvedConversionOperator (denv, fromTy, toTy.Commit, m) | None -> // Otherwise pass the overload resolution failure for error printing in CompileOps UnresolvedOverloading (denv, callerArgs, overloadResolutionFailure, m) @@ -2614,9 +2730,10 @@ and ResolveOverloading csenv permitOptArgs alwaysCheckReturn - (MustUnifyInsideUndo csenv ndeep newTrace cxsln) - (TypesMustSubsumeOrConvertInsideUndo csenv ndeep (WithTrace newTrace) cxsln m) - (ArgsMustSubsumeOrConvertInsideUndo csenv ndeep newTrace cxsln cx.IsSome calledMeth) + (TypesEquiv csenv ndeep (WithTrace newTrace) cxsln) + (TypesMustSubsume csenv ndeep (WithTrace newTrace) cxsln m) + (ReturnTypesMustSubsumeOrConvert csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome m) + (ArgsMustSubsumeOrConvertWithContextualReport csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome calledMeth) reqdRetTyOpt calledMeth) with | OkResult _ -> None @@ -2625,7 +2742,7 @@ and ResolveOverloading None, ErrorD (failOverloading (NoOverloadsFound (methodName, errors, cx))), NoTrace - | [(calledMeth, warns, t)] -> + | [(calledMeth, warns, t, _usesTDC)] -> Some calledMeth, OkResult (warns, ()), WithTrace t | applicableMeths -> @@ -2675,9 +2792,14 @@ and ResolveOverloading 0 /// Check whether one overload is better than another - let better (candidate: CalledMeth<_>, candidateWarnings, _) (other: CalledMeth<_>, otherWarnings, _) = + let better (candidate: CalledMeth<_>, candidateWarnings, _, usesTDC1) (other: CalledMeth<_>, otherWarnings, _, usesTDC2) = let candidateWarnCount = List.length candidateWarnings let otherWarnCount = List.length otherWarnings + + // Prefer methods that don't use type-directed conversion + let c = compare (match usesTDC1 with TypeDirectedConversionUsed.No -> 1 | _ -> 0) (match usesTDC2 with TypeDirectedConversionUsed.No -> 1 | _ -> 0) + if c <> 0 then c else + // Prefer methods that don't give "this code is less generic" warnings // Note: Relies on 'compare' respecting true > false let c = compare (candidateWarnCount = 0) (otherWarnCount = 0) @@ -2779,7 +2901,6 @@ and ResolveOverloading if c <> 0 then c else 0 - let bestMethods = let indexedApplicableMeths = applicableMeths |> List.indexed @@ -2793,7 +2914,7 @@ and ResolveOverloading else None) match bestMethods with - | [(calledMeth, warns, t)] -> Some calledMeth, OkResult (warns, ()), WithTrace t + | [(calledMeth, warns, t, _usesTDC)] -> Some calledMeth, OkResult (warns, ()), WithTrace t | bestMethods -> let methods = let getMethodSlotsAndErrors methodSlot errors = @@ -2809,8 +2930,8 @@ and ResolveOverloading | [] -> match applicableMeths with | [] -> for methodSlot in candidates do yield getMethodSlotsAndErrors methodSlot [] - | m -> for methodSlot, errors, _ in m do yield getMethodSlotsAndErrors methodSlot errors - | m -> for methodSlot, errors, _ in m do yield getMethodSlotsAndErrors methodSlot errors ] + | m -> for methodSlot, errors, _, _ in m do yield getMethodSlotsAndErrors methodSlot errors + | m -> for methodSlot, errors, _, _ in m do yield getMethodSlotsAndErrors methodSlot errors ] let methods = List.concat methods @@ -2833,17 +2954,18 @@ and ResolveOverloading let cxsln = Option.map (fun traitInfo -> (traitInfo, MemberConstraintSolutionOfMethInfo csenv.SolverState m calledMeth.Method calledMeth.CalledTyArgs)) cx match calledMethTrace with | NoTrace -> - return! - // No trace available for CanMemberSigsMatchUpToCheck with ArgsMustSubsumeOrConvert + let! _usesTDC = CanMemberSigsMatchUpToCheck csenv permitOptArgs true - (MustUnify csenv ndeep trace cxsln) - (TypesMustSubsumeOrConvertInsideUndo csenv ndeep trace cxsln m)// REVIEW: this should not be an "InsideUndo" operation - (ArgsMustSubsumeOrConvert csenv ndeep trace cxsln cx.IsSome true) + (TypesEquiv csenv ndeep trace cxsln) // instantiations equal + (TypesMustSubsume csenv ndeep trace cxsln m) // obj can subsume + (ReturnTypesMustSubsumeOrConvert csenv ad ndeep trace cxsln cx.IsSome m) // return can subsume or convert + (ArgsMustSubsumeOrConvert csenv ad ndeep trace cxsln cx.IsSome true) // args can subsume or convert reqdRetTyOpt calledMeth + return () | WithTrace calledMethTrc -> // Re-play existing trace @@ -2852,13 +2974,19 @@ and ResolveOverloading // Unify return type match reqdRetTyOpt with | None -> () - | Some _ when calledMeth.Method.IsConstructor -> () - | Some reqdRetTy -> + | Some reqdRetTy -> let actualRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling - if isByrefTy g reqdRetTy then + if isByrefTy g reqdRetTy.Commit then return! ErrorD(Error(FSComp.SR.tcByrefReturnImplicitlyDereferenced(), m)) else - return! MustUnify csenv ndeep trace cxsln reqdRetTy actualRetTy + match reqdRetTy with + | MustConvertTo(isMethodArg, reqdRetTy) when g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions -> + let! _usesTDC = ReturnTypesMustSubsumeOrConvert csenv ad ndeep trace cxsln isMethodArg m reqdRetTy actualRetTy + return () + | _ -> + let! _usesTDC = TypesEquiv csenv ndeep trace cxsln reqdRetTy.Commit actualRetTy + return () + } | None -> @@ -2886,15 +3014,16 @@ let UnifyUniqueOverloading let ndeep = 0 match calledMethGroup, candidates with | _, [calledMeth] -> trackErrors { - do! + let! _usesTDC = // Only one candidate found - we thus know the types we expect of arguments CanMemberSigsMatchUpToCheck csenv true // permitOptArgs true // always check return type - (MustUnify csenv ndeep NoTrace None) - (TypesMustSubsumeOrConvertInsideUndo csenv ndeep NoTrace None m) - (ArgsMustSubsumeOrConvert csenv ndeep NoTrace None false false) // UnifyUniqueOverloading is not called in case of trait call - pass isConstraint=false + (TypesEquiv csenv ndeep NoTrace None) + (TypesMustSubsume csenv ndeep NoTrace None m) + (ReturnTypesMustSubsumeOrConvert csenv ad ndeep NoTrace None false m) + (ArgsMustSubsumeOrConvert csenv ad ndeep NoTrace None false false) (Some reqdRetTy) calledMeth return true @@ -2946,7 +3075,7 @@ let UndoIfFailed f = // Don't report warnings if we failed trace.Undo() false - | Some warns -> + | Some (warns, _) -> // Report warnings if we succeeded ReportWarnings warns true @@ -2957,9 +3086,9 @@ let UndoIfFailedOrWarnings f = try f trace |> CheckNoErrorsAndGetWarnings - with e -> None + with _ -> None match res with - | Some [] -> + | Some ([], _)-> true | _ -> trace.Undo() diff --git a/src/fsharp/ConstraintSolver.fsi b/src/fsharp/ConstraintSolver.fsi index 086168c2726..fb0d76a2b4e 100644 --- a/src/fsharp/ConstraintSolver.fsi +++ b/src/fsharp/ConstraintSolver.fsi @@ -106,6 +106,17 @@ type OverloadResolutionFailure = * candidates: OverloadInformation list // methodNames may be different (with operators?), this is refactored from original logic to assemble overload failure message * cx: TraitConstraintInfo option +/// Represents known information prior to checking an expression or pattern, e.g. it's expected type +type OverallTy = + /// Each branch of the expression must have the type indicated + | MustEqual of TType + + /// Each branch of the expression must convert to the type indicated + | MustConvertTo of isMethodArg: bool * ty: TType + + /// Represents a point where no subsumption/widening is possible + member Commit: TType + exception ConstraintSolverTupleDiffLengths of displayEnv: DisplayEnv * TType list * TType list * range * range exception ConstraintSolverInfiniteTypes of displayEnv: DisplayEnv * contextInfo: ContextInfo * TType * TType * range * range exception ConstraintSolverTypesNotInEqualityRelation of displayEnv: DisplayEnv * TType * TType * range * range * ContextInfo @@ -141,9 +152,9 @@ type OptionalTrace = val SimplifyMeasuresInTypeScheme: TcGlobals -> bool -> Typars -> TType -> TyparConstraint list -> Typars -val ResolveOverloadingForCall: DisplayEnv -> ConstraintSolverState -> range -> methodName: string -> ndeep: int -> cx: TraitConstraintInfo option -> callerArgs: CallerArgs -> AccessorDomain -> calledMethGroup: CalledMeth list -> permitOptArgs: bool -> reqdRetTyOpt: TType option -> CalledMeth option * OperationResult +val ResolveOverloadingForCall: DisplayEnv -> ConstraintSolverState -> range -> methodName: string -> ndeep: int -> cx: TraitConstraintInfo option -> callerArgs: CallerArgs -> AccessorDomain -> calledMethGroup: CalledMeth list -> permitOptArgs: bool -> reqdRetTyOpt: OverallTy option -> CalledMeth option * OperationResult -val UnifyUniqueOverloading: DisplayEnv -> ConstraintSolverState -> range -> int * int -> string -> AccessorDomain -> CalledMeth list -> TType -> OperationResult +val UnifyUniqueOverloading: DisplayEnv -> ConstraintSolverState -> range -> int * int -> string -> AccessorDomain -> CalledMeth list -> OverallTy -> OperationResult /// Remove the global constraints where these type variables appear in the support of the constraint val EliminateConstraintsForGeneralizedTypars: DisplayEnv -> ConstraintSolverState -> range -> OptionalTrace -> Typars -> unit diff --git a/src/fsharp/ErrorLogger.fs b/src/fsharp/ErrorLogger.fs index cb786b8d393..ed4469d7fcb 100644 --- a/src/fsharp/ErrorLogger.fs +++ b/src/fsharp/ErrorLogger.fs @@ -543,9 +543,9 @@ let ResultD x = OkResult([], x) let CheckNoErrorsAndGetWarnings res = match res with - | OkResult (warns, _) -> Some warns + | OkResult (warns, res2) -> Some (warns, res2) | ErrorResult _ -> None - + /// The bind in the monad. Stop on first error. Accumulate warnings and continue. let (++) res f = match res with @@ -616,7 +616,13 @@ let TryD f g = let rec RepeatWhileD nDeep body = body nDeep ++ (fun x -> if x then RepeatWhileD (nDeep+1) body else CompleteD) -let AtLeastOneD f l = MapD f l ++ (fun res -> ResultD (List.exists id res)) +let inline AtLeastOneD f l = MapD f l ++ (fun res -> ResultD (List.exists id res)) + +let inline AtLeastOne2D f xs ys = List.zip xs ys |> AtLeastOneD (fun (x,y) -> f x y) + +let inline MapReduceD mapper zero reducer l = MapD mapper l ++ (fun res -> ResultD (match res with [] -> zero | _ -> List.reduce reducer res)) + +let inline MapReduce2D mapper zero reducer xs ys = List.zip xs ys |> MapReduceD (fun (x,y) -> mapper x y) zero reducer [] module OperationResult = diff --git a/src/fsharp/ErrorLogger.fsi b/src/fsharp/ErrorLogger.fsi index d5fbb9d46e5..cdecdafdc6f 100644 --- a/src/fsharp/ErrorLogger.fsi +++ b/src/fsharp/ErrorLogger.fsi @@ -256,7 +256,7 @@ val CompleteD: OperationResult val ResultD: x:'a -> OperationResult<'a> -val CheckNoErrorsAndGetWarnings: res:OperationResult<'a> -> exn list option +val CheckNoErrorsAndGetWarnings: res:OperationResult<'a> -> (exn list * 'a) option val ( ++ ): res:OperationResult<'a> -> f:('a -> OperationResult<'b>) -> OperationResult<'b> @@ -302,7 +302,13 @@ val TryD: f:(unit -> OperationResult<'a>) -> g:(exn -> OperationResult<'a>) -> O val RepeatWhileD: nDeep:int -> body:(int -> OperationResult) -> OperationResult -val AtLeastOneD: f:('a -> OperationResult) -> l:'a list -> OperationResult +val inline AtLeastOneD: f:('a -> OperationResult) -> l:'a list -> OperationResult + +val inline AtLeastOne2D: f:('a -> 'b -> OperationResult) -> xs:'a list -> ys:'b list -> OperationResult + +val inline MapReduceD: mapper:('a -> OperationResult<'b>) -> zero: 'b -> reducer: ('b -> 'b -> 'b) -> l:'a list -> OperationResult<'b> + +val inline MapReduce2D: mapper:('a -> 'b -> OperationResult<'c>) -> zero: 'c -> reducer: ('c -> 'c -> 'c) -> xs:'a list -> ys:'b list -> OperationResult<'c> module OperationResult = val inline ignore: res:OperationResult<'a> -> OperationResult diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index e8710b90063..b9fdbd2cadd 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -18,12 +18,12 @@ undefinedNameTypeParameter,"The type parameter %s is not defined." undefinedNamePatternDiscriminator,"The pattern discriminator '%s' is not defined." replaceWithSuggestion,"Replace with '%s'" addIndexerDot,"Add . for indexer access." -listElementHasWrongType,"All elements of a list must be of the same type as the first element, which here is '%s'. This element has type '%s'." -arrayElementHasWrongType,"All elements of an array must be of the same type as the first element, which here is '%s'. This element has type '%s'." +listElementHasWrongType,"All elements of a list must be implicitly convertible to the type of the first element, which here is '%s'. This element has type '%s'." +arrayElementHasWrongType,"All elements of an array must be implicitly convertible to the type of the first element, which here is '%s'. This element has type '%s'." missingElseBranch,"This 'if' expression is missing an 'else' branch. Because 'if' is an expression, and not a statement, add an 'else' branch which also returns a value of type '%s'." ifExpression,"The 'if' expression needs to have type '%s' to satisfy context type requirements. It currently has type '%s'." -elseBranchHasWrongType,"All branches of an 'if' expression must return values of the same type as the first branch, which here is '%s'. This branch returns a value of type '%s'." -followingPatternMatchClauseHasWrongType,"All branches of a pattern match expression must return values of the same type as the first branch, which here is '%s'. This branch returns a value of type '%s'." +elseBranchHasWrongType,"All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is '%s'. This branch returns a value of type '%s'." +followingPatternMatchClauseHasWrongType,"All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is '%s'. This branch returns a value of type '%s'." patternMatchGuardIsNotBool,"A pattern match guard must be of type 'bool', but this 'when' expression is of type '%s'." commaInsteadOfSemicolonInRecord,"A ';' is used to separate field values in records. Consider replacing ',' with ';'." derefInsteadOfNot,"The '!' operator is used to dereference a ref cell. Consider using 'not expr' here." @@ -1529,6 +1529,7 @@ featureNullableOptionalInterop,"nullable optional interop" featureDefaultInterfaceMemberConsumption,"default interface member consumption" featureStringInterpolation,"string interpolation" featureWitnessPassing,"witness passing for trait constraints in F# quotations" +featureAdditionalImplicitConversions,"additional type-directed conversions" featureStructActivePattern,"struct representation for active patterns" featureRelaxWhitespace2,"whitespace relaxation v2" 3353,fsiInvalidDirective,"Invalid directive '#%s %s'" @@ -1557,6 +1558,11 @@ forFormatInvalidForInterpolated4,"Interpolated strings used as type IFormattable 3384,scriptSdkNotDeterminedUnexpected,"The .NET SDK for this script could not be determined. If the script is in a directory using a 'global.json' then ensure the relevant .NET SDK is installed. Unexpected error '%s'." 3384,scriptSdkNotDeterminedNoHost,"The .NET SDK for this script could not be determined. dotnet.exe could not be found ensure a .NET SDK is installed." 3385,tcInvalidStructReturn,"The use of '[]' on values, functions and methods is only allowed on partial active pattern definitions" +3387,tcAmbiguousImplicitConversion,"This expression has type '%s' and is only made compatible with type '%s' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:%s" +3388,tcSubsumptionImplicitConversionUsed,"This expression implicitly converts type '%s' to type '%s'. See https://aka.ms/fsharp-implicit-convs." +3389,tcBuiltInImplicitConversionUsed,"This expression uses a built-in implicit conversion to convert type '%s' to type '%s'. See https://aka.ms/fsharp-implicit-convs." +3390,tcImplicitConversionUsedForMethodArg,"This expression uses the implicit conversion '%s' to convert type '%s' to type '%s'." +3391,tcImplicitConversionUsedForNonMethodArg,"This expression uses the implicit conversion '%s' to convert type '%s' to type '%s'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\"." #3501 "This construct is not supported by your version of the F# compiler" CompilerMessage(ExperimentalAttributeMessages.NotSupportedYet, 3501, IsError=true) 3390,xmlDocBadlyFormed,"This XML comment is invalid: '%s'" 3390,xmlDocMissingParameterName,"This XML comment is invalid: missing 'name' attribute for parameter or parameter reference" diff --git a/src/fsharp/FSharp.Core/prim-types.fsi b/src/fsharp/FSharp.Core/prim-types.fsi index baa9a5127b2..917abe58298 100644 --- a/src/fsharp/FSharp.Core/prim-types.fsi +++ b/src/fsharp/FSharp.Core/prim-types.fsi @@ -2410,6 +2410,8 @@ namespace Microsoft.FSharp.Core /// /// The input value /// + /// The F# compiler ignored this method when determining possible type-directed conversions. Instead, use Some or None explicitly. + /// /// An option representing the value. /// static member op_Implicit : value:'T -> 'T option @@ -2485,6 +2487,8 @@ namespace Microsoft.FSharp.Core /// /// The input value /// + /// The F# compiler ignored this method when determining possible type-directed conversions. Instead, use Some or None explicitly. + /// /// A voption representing the value. /// static member op_Implicit: value: 'T -> 'T voption diff --git a/src/fsharp/InfoReader.fs b/src/fsharp/InfoReader.fs index b015ad466e0..dbd8ec3ba01 100644 --- a/src/fsharp/InfoReader.fs +++ b/src/fsharp/InfoReader.fs @@ -122,7 +122,7 @@ type PropertyCollector(g, amap, m, ty, optFilter, ad) = | _ -> props.[pinfo] <- pinfo - member x.Collect(membInfo: ValMemberInfo, vref: ValRef) = + member _.Collect(membInfo: ValMemberInfo, vref: ValRef) = match membInfo.MemberFlags.MemberKind with | SynMemberKind.PropertyGet -> let pinfo = FSProp(g, ty, Some vref, None) @@ -135,7 +135,7 @@ type PropertyCollector(g, amap, m, ty, optFilter, ad) = | _ -> () - member x.Close() = [ for KeyValue(_, pinfo) in props -> pinfo ] + member _.Close() = [ for KeyValue(_, pinfo) in props -> pinfo ] let rec GetImmediateIntrinsicPropInfosOfTypeAux (optFilter, ad) g amap m origTy metadataTy = @@ -252,6 +252,44 @@ type HierarchyItem = | EventItem of EventInfo list | ILFieldItem of ILFieldInfo list +//------------------------------------------------------------------------- +// Collecting methods and properties taking into account hiding rules in the hierarchy + + +/// Indicates if we prefer overrides or abstract slots. +type FindMemberFlag = + /// Prefer items toward the top of the hierarchy, which we do if the items are virtual + /// but not when resolving base calls. + | IgnoreOverrides + /// Get overrides instead of abstract slots when measuring whether a class/interface implements all its required slots. + | PreferOverrides + +/// The input list is sorted from most-derived to least-derived type, so any System.Object methods +/// are at the end of the list. Return a filtered list where prior/subsequent members matching by name and +/// that are in the same equivalence class have been removed. We keep a name-indexed table to +/// be more efficient when we check to see if we've already seen a particular named method. +type private IndexedList<'T>(itemLists: 'T list list, itemsByName: NameMultiMap<'T>) = + + /// Get the item sets + member _.Items = itemLists + + /// Get the items with a particular name + member _.ItemsWithName(nm) = NameMultiMap.find nm itemsByName + + /// Add new items, extracting the names using the given function. + member _.AddItems(items, nmf) = IndexedList<'T>(items :: itemLists, List.foldBack (fun x acc -> NameMultiMap.add (nmf x) x acc) items itemsByName ) + + /// Get an empty set of items + static member Empty = IndexedList<'T>([], NameMultiMap.empty) + + /// Filter a set of new items to add according to the content of the list. Only keep an item + /// if it passes 'keepTest' for all matching items already in the list. + member x.FilterNewItems keepTest nmf itemsToAdd = + // Have we already seen an item with the same name and that is in the same equivalence class? + // If so, ignore this one. Note we can check against the original incoming 'ilist' because we are assuming that + // none the elements of 'itemsToAdd' are equivalent. + itemsToAdd |> List.filter (fun item -> List.forall (keepTest item) (x.ItemsWithName(nmf item))) + /// An InfoReader is an object to help us read and cache infos. /// We create one of these for each file we typecheck. type InfoReader(g: TcGlobals, amap: Import.ImportMap) as this = @@ -434,6 +472,145 @@ type InfoReader(g: TcGlobals, amap: Import.ImportMap) as this = ||> List.fold (fun acc ty -> GetImmediateIntrinsicOverrideMethodSetsOfType optFilter m interfaceTys ty acc) |> FilterMostSpecificMethInfoSets g amap m + /// Add all the items to the IndexedList, preferring the ones in the super-types. This is used to hide methods + /// in super classes and/or hide overrides of methods in subclasses. + /// + /// Assume no items in 'items' are equivalent according to 'equivTest'. This is valid because each step in a + /// .NET class hierarchy introduces a consistent set of methods, none of which hide each other within the + /// given set. This is an important optimization because it means we don't have filter for equivalence between the + /// large overload sets introduced by methods like System.WriteLine. + /// + /// Assume items can be given names by 'nmf', where two items with different names are + /// not equivalent. + + static let FilterItemsInSubTypesBasedOnItemsInSuperTypes nmf keepTest itemLists = + let rec loop itemLists = + match itemLists with + | [] -> IndexedList.Empty + | items :: itemsInSuperTypes -> + let ilist = loop itemsInSuperTypes + let itemsToAdd = ilist.FilterNewItems keepTest nmf items + ilist.AddItems(itemsToAdd, nmf) + (loop itemLists).Items + + /// Add all the items to the IndexedList, preferring the ones in the sub-types. + static let FilterItemsInSuperTypesBasedOnItemsInSubTypes nmf keepTest itemLists = + let rec loop itemLists (indexedItemsInSubTypes: IndexedList<_>) = + match itemLists with + | [] -> List.rev indexedItemsInSubTypes.Items + | items :: itemsInSuperTypes -> + let itemsToAdd = items |> List.filter (fun item -> keepTest item (indexedItemsInSubTypes.ItemsWithName(nmf item))) + let ilist = indexedItemsInSubTypes.AddItems(itemsToAdd, nmf) + loop itemsInSuperTypes ilist + + loop itemLists IndexedList.Empty + + static let ExcludeItemsInSuperTypesBasedOnEquivTestWithItemsInSubTypes nmf equivTest itemLists = + FilterItemsInSuperTypesBasedOnItemsInSubTypes nmf (fun item1 items -> not (items |> List.exists (fun item2 -> equivTest item1 item2))) itemLists + + /// Filter the overrides of methods or properties, either keeping the overrides or keeping the dispatch slots. + static let FilterOverrides findFlag (isVirt:'a->bool, isNewSlot, isDefiniteOverride, isFinal, equivSigs, nmf:'a->string) items = + let equivVirts x y = isVirt x && isVirt y && equivSigs x y + + match findFlag with + | PreferOverrides -> + items + // For each F#-declared override, get rid of any equivalent abstract member in the same type + // This is because F# abstract members with default overrides give rise to two members with the + // same logical signature in the same type, e.g. + // type ClassType1() = + // abstract VirtualMethod1: string -> int + // default x.VirtualMethod1(s) = 3 + + |> List.map (fun items -> + let definiteOverrides = items |> List.filter isDefiniteOverride + items |> List.filter (fun item -> (isDefiniteOverride item || not (List.exists (equivVirts item) definiteOverrides)))) + + // only keep virtuals that are not signature-equivalent to virtuals in subtypes + |> ExcludeItemsInSuperTypesBasedOnEquivTestWithItemsInSubTypes nmf equivVirts + | IgnoreOverrides -> + let equivNewSlots x y = isNewSlot x && isNewSlot y && equivSigs x y + items + // Remove any F#-declared overrides. These may occur in the same type as the abstract member (unlike with .NET metadata) + // Include any 'newslot' declared methods. + |> List.map (List.filter (fun x -> not (isDefiniteOverride x))) + + // Remove any virtuals that are signature-equivalent to virtuals in subtypes, except for newslots + // That is, keep if it's + /// (a) not virtual + // (b) is a new slot or + // (c) not equivalent + // We keep virtual finals around for error detection later on + |> FilterItemsInSubTypesBasedOnItemsInSuperTypes nmf (fun newItem priorItem -> + (isVirt newItem && isFinal newItem) || not (isVirt newItem) || isNewSlot newItem || not (equivVirts newItem priorItem) ) + + // Remove any abstract slots in supertypes that are (a) hidden by another newslot and (b) implemented + // We leave unimplemented ones around to give errors, e.g. for + // [] + // type PA() = + // abstract M : int -> unit + // + // [] + // type PB<'a>() = + // inherit PA() + // abstract M : 'a -> unit + // + // [] + // type PC() = + // inherit PB() + // // Here, PA.M and PB.M have the same signature, so PA.M is unimplementable. + // // REVIEW: in future we may give a friendly error at this point + // + // type PD() = + // inherit PC() + // override this.M(x: int) = () + + |> FilterItemsInSuperTypesBasedOnItemsInSubTypes nmf (fun item1 superTypeItems -> + not (isNewSlot item1 && + superTypeItems |> List.exists (equivNewSlots item1) && + superTypeItems |> List.exists (fun item2 -> isDefiniteOverride item1 && equivVirts item1 item2))) + + + /// Filter the overrides of methods, either keeping the overrides or keeping the dispatch slots. + static let FilterOverridesOfMethInfos findFlag g amap m minfos = + minfos + |> FilterOverrides findFlag + ((fun (minfo: MethInfo) -> minfo.IsVirtual), + (fun minfo -> minfo.IsNewSlot), + (fun minfo -> minfo.IsDefiniteFSharpOverride), + (fun minfo -> minfo.IsFinal), + MethInfosEquivByNameAndSig EraseNone true g amap m, + (fun minfo -> minfo.LogicalName)) + + /// Filter the overrides of properties, either keeping the overrides or keeping the dispatch slots. + static let FilterOverridesOfPropInfos findFlag g amap m props = + props + |> FilterOverrides findFlag + ((fun (pinfo: PropInfo) -> pinfo.IsVirtualProperty), + (fun pinfo -> pinfo.IsNewSlot), + (fun pinfo -> pinfo.IsDefiniteFSharpOverride), + (fun _ -> false), + PropInfosEquivByNameAndSig EraseNone g amap m, + (fun pinfo -> pinfo.PropertyName)) + + /// Exclude methods from super types which have the same signature as a method in a more specific type. + static let ExcludeHiddenOfMethInfosImpl g amap m (minfos: MethInfo list list) = + minfos + |> ExcludeItemsInSuperTypesBasedOnEquivTestWithItemsInSubTypes + (fun minfo -> minfo.LogicalName) + (fun m1 m2 -> + // only hide those truly from super classes + not (tyconRefEq g m1.DeclaringTyconRef m2.DeclaringTyconRef) && + MethInfosEquivByNameAndPartialSig EraseNone true g amap m m1 m2) + + |> List.concat + + /// Exclude properties from super types which have the same name as a property in a more specific type. + static let ExcludeHiddenOfPropInfosImpl g amap m pinfos = + pinfos + |> ExcludeItemsInSuperTypesBasedOnEquivTestWithItemsInSubTypes (fun (pinfo: PropInfo) -> pinfo.PropertyName) (PropInfosEquivByNameAndPartialSig EraseNone g amap m) + |> List.concat + /// Make a cache for function 'f' keyed by type (plus some additional 'flags') that only /// caches computations for monomorphic types. @@ -450,34 +627,48 @@ type InfoReader(g: TcGlobals, amap: Import.ImportMap) as this = keyComparer= { new System.Collections.Generic.IEqualityComparer<_> with - member x.Equals((flags1, _, typ1), (flags2, _, typ2)) = + member _.Equals((flags1, _, typ1), (flags2, _, typ2)) = // Ignoring the ranges - that's OK. flagsEq.Equals(flags1, flags2) && match stripTyEqns g typ1, stripTyEqns g typ2 with | TType_app(tcref1, []), TType_app(tcref2, []) -> tyconRefEq g tcref1 tcref2 | _ -> false - member x.GetHashCode((flags, _, ty)) = + member _.GetHashCode((flags, _, ty)) = // Ignoring the ranges - that's OK. flagsEq.GetHashCode flags + (match stripTyEqns g ty with | TType_app(tcref, []) -> hash tcref.LogicalName | _ -> 0) }) + let FindImplicitConversionsUncached (ad, m, ty) = + if isTyparTy g ty then + [] + // F# ignores the op_Implicit conversions defined on the 'Option' and 'ValueOption' types + elif isOptionTy g ty || isValueOptionTy g ty then + [] + else + this.TryFindIntrinsicMethInfo m ad "op_Implicit" ty + let hashFlags0 = - { new System.Collections.Generic.IEqualityComparer<_> with - member x.GetHashCode((filter: string option, ad: AccessorDomain, _allowMultiIntfInst1)) = hash filter + AccessorDomain.CustomGetHashCode ad - member x.Equals((filter1, ad1, allowMultiIntfInst1), (filter2, ad2, allowMultiIntfInst2)) = + { new System.Collections.Generic.IEqualityComparer with + member _.GetHashCode((filter: string option, ad: AccessorDomain, _allowMultiIntfInst1)) = hash filter + AccessorDomain.CustomGetHashCode ad + member _.Equals((filter1, ad1, allowMultiIntfInst1), (filter2, ad2, allowMultiIntfInst2)) = (filter1 = filter2) && AccessorDomain.CustomEquals(g, ad1, ad2) && allowMultiIntfInst1 = allowMultiIntfInst2 } let hashFlags1 = - { new System.Collections.Generic.IEqualityComparer<_> with - member x.GetHashCode((filter: string option, ad: AccessorDomain)) = hash filter + AccessorDomain.CustomGetHashCode ad - member x.Equals((filter1, ad1), (filter2, ad2)) = (filter1 = filter2) && AccessorDomain.CustomEquals(g, ad1, ad2) } + { new System.Collections.Generic.IEqualityComparer with + member _.GetHashCode((filter: string option, ad: AccessorDomain)) = hash filter + AccessorDomain.CustomGetHashCode ad + member _.Equals((filter1, ad1), (filter2, ad2)) = (filter1 = filter2) && AccessorDomain.CustomEquals(g, ad1, ad2) } let hashFlags2 = - { new System.Collections.Generic.IEqualityComparer<_> with - member x.GetHashCode((nm: string, ad: AccessorDomain)) = hash nm + AccessorDomain.CustomGetHashCode ad - member x.Equals((nm1, ad1), (nm2, ad2)) = (nm1 = nm2) && AccessorDomain.CustomEquals(g, ad1, ad2) } + { new System.Collections.Generic.IEqualityComparer with + member _.GetHashCode((nm: string, ad: AccessorDomain)) = hash nm + AccessorDomain.CustomGetHashCode ad + member _.Equals((nm1, ad1), (nm2, ad2)) = (nm1 = nm2) && AccessorDomain.CustomEquals(g, ad1, ad2) } + + let hashFlags3 = + { new System.Collections.Generic.IEqualityComparer with + member _.GetHashCode((ad: AccessorDomain)) = AccessorDomain.CustomGetHashCode ad + member _.Equals((ad1), (ad2)) = AccessorDomain.CustomEquals(g, ad1, ad2) } let methodInfoCache = MakeInfoCache GetIntrinsicMethodSetsUncached hashFlags0 let propertyInfoCache = MakeInfoCache GetIntrinsicPropertySetsUncached hashFlags0 @@ -489,6 +680,7 @@ type InfoReader(g: TcGlobals, amap: Import.ImportMap) as this = let entireTypeHierarchyCache = MakeInfoCache GetEntireTypeHierarchyUncached HashIdentity.Structural let primaryTypeHierarchyCache = MakeInfoCache GetPrimaryTypeHierarchyUncached HashIdentity.Structural + let implicitConversionCache = MakeInfoCache FindImplicitConversionsUncached hashFlags3 // Runtime feature support @@ -503,33 +695,34 @@ type InfoReader(g: TcGlobals, amap: Import.ImportMap) as this = let isRuntimeFeatureDefaultImplementationsOfInterfacesSupported = lazy isRuntimeFeatureSupported this "DefaultImplementationsOfInterfaces" - member x.g = g - member x.amap = amap + member _.g = g + member _.amap = amap /// Read the raw method sets of a type, including inherited ones. Cache the result for monomorphic types - member x.GetRawIntrinsicMethodSetsOfType (optFilter, ad, allowMultiIntfInst, m, ty) = + member _.GetRawIntrinsicMethodSetsOfType (optFilter, ad, allowMultiIntfInst, m, ty) = methodInfoCache.Apply(((optFilter, ad, allowMultiIntfInst), m, ty)) /// Read the raw property sets of a type, including inherited ones. Cache the result for monomorphic types - member x.GetRawIntrinsicPropertySetsOfType (optFilter, ad, allowMultiIntfInst, m, ty) = + member _.GetRawIntrinsicPropertySetsOfType (optFilter, ad, allowMultiIntfInst, m, ty) = propertyInfoCache.Apply(((optFilter, ad, allowMultiIntfInst), m, ty)) /// Read the record or class fields of a type, including inherited ones. Cache the result for monomorphic types. - member x.GetRecordOrClassFieldsOfType (optFilter, ad, m, ty) = + member _.GetRecordOrClassFieldsOfType (optFilter, ad, m, ty) = recdOrClassFieldInfoCache.Apply(((optFilter, ad), m, ty)) /// Read the IL fields of a type, including inherited ones. Cache the result for monomorphic types. - member x.GetILFieldInfosOfType (optFilter, ad, m, ty) = + member _.GetILFieldInfosOfType (optFilter, ad, m, ty) = ilFieldInfoCache.Apply(((optFilter, ad), m, ty)) - member x.GetImmediateIntrinsicEventsOfType (optFilter, ad, m, ty) = ComputeImmediateIntrinsicEventsOfType (optFilter, ad) m ty + member _.GetImmediateIntrinsicEventsOfType (optFilter, ad, m, ty) = + ComputeImmediateIntrinsicEventsOfType (optFilter, ad) m ty /// Read the events of a type, including inherited ones. Cache the result for monomorphic types. - member x.GetEventInfosOfType (optFilter, ad, m, ty) = + member _.GetEventInfosOfType (optFilter, ad, m, ty) = eventInfoCache.Apply(((optFilter, ad), m, ty)) /// Try and find a record or class field for a type. - member x.TryFindRecdOrClassFieldInfoOfType (nm, m, ty) = + member _.TryFindRecdOrClassFieldInfoOfType (nm, m, ty) = match recdOrClassFieldInfoCache.Apply((Some nm, AccessibleFromSomewhere), m, ty) with | [] -> ValueNone | [single] -> ValueSome single @@ -545,28 +738,110 @@ type InfoReader(g: TcGlobals, amap: Import.ImportMap) as this = | _ -> failwith "unexpected multiple fields with same name" // Because it should have been already reported as duplicate fields /// Try and find an item with the given name in a type. - member x.TryFindNamedItemOfType (nm, ad, m, ty) = + member _.TryFindNamedItemOfType (nm, ad, m, ty) = namedItemsCache.Apply(((nm, ad), m, ty)) /// Read the raw method sets of a type that are the most specific overrides. Cache the result for monomorphic types - member x.GetIntrinsicMostSpecificOverrideMethodSetsOfType (optFilter, ad, allowMultiIntfInst, m, ty) = + member _.GetIntrinsicMostSpecificOverrideMethodSetsOfType (optFilter, ad, allowMultiIntfInst, m, ty) = mostSpecificOverrideMethodInfoCache.Apply(((optFilter, ad, allowMultiIntfInst), m, ty)) /// Get the super-types of a type, including interface types. - member x.GetEntireTypeHierarchy (allowMultiIntfInst, m, ty) = + member _.GetEntireTypeHierarchy (allowMultiIntfInst, m, ty) = entireTypeHierarchyCache.Apply((allowMultiIntfInst, m, ty)) /// Get the super-types of a type, excluding interface types. - member x.GetPrimaryTypeHierarchy (allowMultiIntfInst, m, ty) = + member _.GetPrimaryTypeHierarchy (allowMultiIntfInst, m, ty) = primaryTypeHierarchyCache.Apply((allowMultiIntfInst, m, ty)) /// Check if the given language feature is supported by the runtime. - member x.IsLanguageFeatureRuntimeSupported langFeature = + member _.IsLanguageFeatureRuntimeSupported langFeature = match langFeature with // Both default and static interface method consumption features are tied to the runtime support of DIMs. | LanguageFeature.DefaultInterfaceMemberConsumption -> isRuntimeFeatureDefaultImplementationsOfInterfacesSupported.Value | _ -> true + /// Get the declared constructors of any F# type + member infoReader.GetIntrinsicConstructorInfosOfTypeAux m origTy metadataTy = + protectAssemblyExploration [] (fun () -> + let g = infoReader.g + let amap = infoReader.amap + match metadataOfTy g metadataTy with + #if !NO_EXTENSIONTYPING + | ProvidedTypeMetadata info -> + let st = info.ProvidedType + [ for ci in st.PApplyArray((fun st -> st.GetConstructors()), "GetConstructors", m) do + yield ProvidedMeth(amap, ci.Coerce(m), None, m) ] + #endif + | ILTypeMetadata _ -> + let tinfo = ILTypeInfo.FromType g origTy + tinfo.RawMetadata.Methods.FindByName ".ctor" + |> List.filter (fun md -> md.IsConstructor) + |> List.map (fun mdef -> MethInfo.CreateILMeth (amap, m, origTy, mdef)) + + | FSharpOrArrayOrByrefOrTupleOrExnTypeMetadata -> + // Tuple types also support constructors. In this case convert to the .NET Tuple type that carries metadata and try again + // Function types also support constructors. In this case convert to the FSharpFunc type that carries metadata and try again + if isAnyTupleTy g metadataTy || isFunTy g metadataTy then + let betterMetadataTy = convertToTypeWithMetadataIfPossible g metadataTy + infoReader.GetIntrinsicConstructorInfosOfTypeAux m origTy betterMetadataTy + else + match tryTcrefOfAppTy g metadataTy with + | ValueNone -> [] + | ValueSome tcref -> + tcref.MembersOfFSharpTyconByName + |> NameMultiMap.find ".ctor" + |> List.choose(fun vref -> + match vref.MemberInfo with + | Some membInfo when (membInfo.MemberFlags.MemberKind = SynMemberKind.Constructor) -> Some vref + | _ -> None) + |> List.map (fun x -> FSMeth(g, origTy, x, None)) + ) + + static member ExcludeHiddenOfMethInfos g amap m minfos = + ExcludeHiddenOfMethInfosImpl g amap m minfos + + static member ExcludeHiddenOfPropInfos g amap m pinfos = + ExcludeHiddenOfPropInfosImpl g amap m pinfos + + /// Get the sets of intrinsic methods in the hierarchy (not including extension methods) + member infoReader.GetIntrinsicMethInfoSetsOfType optFilter ad allowMultiIntfInst findFlag m ty = + infoReader.GetRawIntrinsicMethodSetsOfType(optFilter, ad, allowMultiIntfInst, m, ty) + |> FilterOverridesOfMethInfos findFlag infoReader.g infoReader.amap m + + /// Get the sets intrinsic properties in the hierarchy (not including extension properties) + member infoReader.GetIntrinsicPropInfoSetsOfType optFilter ad allowMultiIntfInst findFlag m ty = + infoReader.GetRawIntrinsicPropertySetsOfType(optFilter, ad, allowMultiIntfInst, m, ty) + |> FilterOverridesOfPropInfos findFlag infoReader.g infoReader.amap m + + /// Get the flattened list of intrinsic methods in the hierarchy + member infoReader.GetIntrinsicMethInfosOfType optFilter ad allowMultiIntfInst findFlag m ty = + infoReader.GetIntrinsicMethInfoSetsOfType optFilter ad allowMultiIntfInst findFlag m ty |> List.concat + + /// Get the flattened list of intrinsic properties in the hierarchy + member infoReader.GetIntrinsicPropInfosOfType optFilter ad allowMultiIntfInst findFlag m ty = + infoReader.GetIntrinsicPropInfoSetsOfType optFilter ad allowMultiIntfInst findFlag m ty |> List.concat + + member infoReader.TryFindIntrinsicNamedItemOfType (nm, ad) findFlag m ty = + match infoReader.TryFindNamedItemOfType(nm, ad, m, ty) with + | Some item -> + match item with + | PropertyItem psets -> Some(PropertyItem (psets |> FilterOverridesOfPropInfos findFlag infoReader.g infoReader.amap m)) + | MethodItem msets -> Some(MethodItem (msets |> FilterOverridesOfMethInfos findFlag infoReader.g infoReader.amap m)) + | _ -> Some(item) + | None -> None + + /// Try to detect the existence of a method on a type. + member infoReader.TryFindIntrinsicMethInfo m ad nm ty = + infoReader.GetIntrinsicMethInfosOfType (Some nm) ad AllowMultiIntfInstantiations.Yes IgnoreOverrides m ty + + /// Try to find a particular named property on a type. Only used to ensure that local 'let' definitions and property names + /// are distinct, a somewhat adhoc check in tc.fs. + member infoReader.TryFindIntrinsicPropInfo m ad nm ty = + infoReader.GetIntrinsicPropInfosOfType (Some nm) ad AllowMultiIntfInstantiations.Yes IgnoreOverrides m ty + + member _.FindImplicitConversions m ad ty = + implicitConversionCache.Apply((ad, m, ty)) + let private tryLanguageFeatureRuntimeErrorAux (infoReader: InfoReader) langFeature m error = if not (infoReader.IsLanguageFeatureRuntimeSupported langFeature) then let featureStr = infoReader.g.langVersion.GetFeatureString langFeature @@ -584,263 +859,35 @@ let checkLanguageFeatureRuntimeErrorRecover infoReader langFeature m = let tryLanguageFeatureRuntimeErrorRecover infoReader langFeature m = tryLanguageFeatureRuntimeErrorAux infoReader langFeature m errorR -/// Get the declared constructors of any F# type -let rec GetIntrinsicConstructorInfosOfTypeAux (infoReader: InfoReader) m origTy metadataTy = - protectAssemblyExploration [] (fun () -> - let g = infoReader.g - let amap = infoReader.amap - match metadataOfTy g metadataTy with -#if !NO_EXTENSIONTYPING - | ProvidedTypeMetadata info -> - let st = info.ProvidedType - [ for ci in st.PApplyArray((fun st -> st.GetConstructors()), "GetConstructors", m) do - yield ProvidedMeth(amap, ci.Coerce(m), None, m) ] -#endif - | ILTypeMetadata _ -> - let tinfo = ILTypeInfo.FromType g origTy - tinfo.RawMetadata.Methods.FindByName ".ctor" - |> List.filter (fun md -> md.IsConstructor) - |> List.map (fun mdef -> MethInfo.CreateILMeth (amap, m, origTy, mdef)) - - | FSharpOrArrayOrByrefOrTupleOrExnTypeMetadata -> - // Tuple types also support constructors. In this case convert to the .NET Tuple type that carries metadata and try again - // Function types also support constructors. In this case convert to the FSharpFunc type that carries metadata and try again - if isAnyTupleTy g metadataTy || isFunTy g metadataTy then - let betterMetadataTy = convertToTypeWithMetadataIfPossible g metadataTy - GetIntrinsicConstructorInfosOfTypeAux infoReader m origTy betterMetadataTy - else - match tryTcrefOfAppTy g metadataTy with - | ValueNone -> [] - | ValueSome tcref -> - tcref.MembersOfFSharpTyconByName - |> NameMultiMap.find ".ctor" - |> List.choose(fun vref -> - match vref.MemberInfo with - | Some membInfo when (membInfo.MemberFlags.MemberKind = SynMemberKind.Constructor) -> Some vref - | _ -> None) - |> List.map (fun x -> FSMeth(g, origTy, x, None)) - ) - -let GetIntrinsicConstructorInfosOfType infoReader m ty = - GetIntrinsicConstructorInfosOfTypeAux infoReader m ty ty - -//------------------------------------------------------------------------- -// Collecting methods and properties taking into account hiding rules in the hierarchy - - -/// Indicates if we prefer overrides or abstract slots. -type FindMemberFlag = - /// Prefer items toward the top of the hierarchy, which we do if the items are virtual - /// but not when resolving base calls. - | IgnoreOverrides - /// Get overrides instead of abstract slots when measuring whether a class/interface implements all its required slots. - | PreferOverrides - -/// The input list is sorted from most-derived to least-derived type, so any System.Object methods -/// are at the end of the list. Return a filtered list where prior/subsequent members matching by name and -/// that are in the same equivalence class have been removed. We keep a name-indexed table to -/// be more efficient when we check to see if we've already seen a particular named method. -type private IndexedList<'T>(itemLists: 'T list list, itemsByName: NameMultiMap<'T>) = - - /// Get the item sets - member x.Items = itemLists - - /// Get the items with a particular name - member x.ItemsWithName(nm) = NameMultiMap.find nm itemsByName - - /// Add new items, extracting the names using the given function. - member x.AddItems(items, nmf) = IndexedList<'T>(items :: itemLists, List.foldBack (fun x acc -> NameMultiMap.add (nmf x) x acc) items itemsByName ) - - /// Get an empty set of items - static member Empty = IndexedList<'T>([], NameMultiMap.empty) - - /// Filter a set of new items to add according to the content of the list. Only keep an item - /// if it passes 'keepTest' for all matching items already in the list. - member x.FilterNewItems keepTest nmf itemsToAdd = - // Have we already seen an item with the same name and that is in the same equivalence class? - // If so, ignore this one. Note we can check against the original incoming 'ilist' because we are assuming that - // none the elements of 'itemsToAdd' are equivalent. - itemsToAdd |> List.filter (fun item -> List.forall (keepTest item) (x.ItemsWithName(nmf item))) - -/// Add all the items to the IndexedList, preferring the ones in the super-types. This is used to hide methods -/// in super classes and/or hide overrides of methods in subclasses. -/// -/// Assume no items in 'items' are equivalent according to 'equivTest'. This is valid because each step in a -/// .NET class hierarchy introduces a consistent set of methods, none of which hide each other within the -/// given set. This is an important optimization because it means we don't have filter for equivalence between the -/// large overload sets introduced by methods like System.WriteLine. -/// -/// Assume items can be given names by 'nmf', where two items with different names are -/// not equivalent. - -let private FilterItemsInSubTypesBasedOnItemsInSuperTypes nmf keepTest itemLists = - let rec loop itemLists = - match itemLists with - | [] -> IndexedList.Empty - | items :: itemsInSuperTypes -> - let ilist = loop itemsInSuperTypes - let itemsToAdd = ilist.FilterNewItems keepTest nmf items - ilist.AddItems(itemsToAdd, nmf) - (loop itemLists).Items - -/// Add all the items to the IndexedList, preferring the ones in the sub-types. -let private FilterItemsInSuperTypesBasedOnItemsInSubTypes nmf keepTest itemLists = - let rec loop itemLists (indexedItemsInSubTypes: IndexedList<_>) = - match itemLists with - | [] -> List.rev indexedItemsInSubTypes.Items - | items :: itemsInSuperTypes -> - let itemsToAdd = items |> List.filter (fun item -> keepTest item (indexedItemsInSubTypes.ItemsWithName(nmf item))) - let ilist = indexedItemsInSubTypes.AddItems(itemsToAdd, nmf) - loop itemsInSuperTypes ilist - - loop itemLists IndexedList.Empty - -let private ExcludeItemsInSuperTypesBasedOnEquivTestWithItemsInSubTypes nmf equivTest itemLists = - FilterItemsInSuperTypesBasedOnItemsInSubTypes nmf (fun item1 items -> not (items |> List.exists (fun item2 -> equivTest item1 item2))) itemLists - -/// Filter the overrides of methods or properties, either keeping the overrides or keeping the dispatch slots. -let private FilterOverrides findFlag (isVirt:'a->bool, isNewSlot, isDefiniteOverride, isFinal, equivSigs, nmf:'a->string) items = - let equivVirts x y = isVirt x && isVirt y && equivSigs x y - - match findFlag with - | PreferOverrides -> - items - // For each F#-declared override, get rid of any equivalent abstract member in the same type - // This is because F# abstract members with default overrides give rise to two members with the - // same logical signature in the same type, e.g. - // type ClassType1() = - // abstract VirtualMethod1: string -> int - // default x.VirtualMethod1(s) = 3 - - |> List.map (fun items -> - let definiteOverrides = items |> List.filter isDefiniteOverride - items |> List.filter (fun item -> (isDefiniteOverride item || not (List.exists (equivVirts item) definiteOverrides)))) - - // only keep virtuals that are not signature-equivalent to virtuals in subtypes - |> ExcludeItemsInSuperTypesBasedOnEquivTestWithItemsInSubTypes nmf equivVirts - | IgnoreOverrides -> - let equivNewSlots x y = isNewSlot x && isNewSlot y && equivSigs x y - items - // Remove any F#-declared overrides. These may occur in the same type as the abstract member (unlike with .NET metadata) - // Include any 'newslot' declared methods. - |> List.map (List.filter (fun x -> not (isDefiniteOverride x))) - - // Remove any virtuals that are signature-equivalent to virtuals in subtypes, except for newslots - // That is, keep if it's - /// (a) not virtual - // (b) is a new slot or - // (c) not equivalent - // We keep virtual finals around for error detection later on - |> FilterItemsInSubTypesBasedOnItemsInSuperTypes nmf (fun newItem priorItem -> - (isVirt newItem && isFinal newItem) || not (isVirt newItem) || isNewSlot newItem || not (equivVirts newItem priorItem) ) - - // Remove any abstract slots in supertypes that are (a) hidden by another newslot and (b) implemented - // We leave unimplemented ones around to give errors, e.g. for - // [] - // type PA() = - // abstract M : int -> unit - // - // [] - // type PB<'a>() = - // inherit PA() - // abstract M : 'a -> unit - // - // [] - // type PC() = - // inherit PB() - // // Here, PA.M and PB.M have the same signature, so PA.M is unimplementable. - // // REVIEW: in future we may give a friendly error at this point - // - // type PD() = - // inherit PC() - // override this.M(x: int) = () - - |> FilterItemsInSuperTypesBasedOnItemsInSubTypes nmf (fun item1 superTypeItems -> - not (isNewSlot item1 && - superTypeItems |> List.exists (equivNewSlots item1) && - superTypeItems |> List.exists (fun item2 -> isDefiniteOverride item1 && equivVirts item1 item2))) +let GetIntrinsicConstructorInfosOfType (infoReader: InfoReader) m ty = + infoReader.GetIntrinsicConstructorInfosOfTypeAux m ty ty - -/// Filter the overrides of methods, either keeping the overrides or keeping the dispatch slots. -let private FilterOverridesOfMethInfos findFlag g amap m minfos = - minfos - |> FilterOverrides findFlag - ((fun (minfo: MethInfo) -> minfo.IsVirtual), - (fun minfo -> minfo.IsNewSlot), - (fun minfo -> minfo.IsDefiniteFSharpOverride), - (fun minfo -> minfo.IsFinal), - MethInfosEquivByNameAndSig EraseNone true g amap m, - (fun minfo -> minfo.LogicalName)) - -/// Filter the overrides of properties, either keeping the overrides or keeping the dispatch slots. -let private FilterOverridesOfPropInfos findFlag g amap m props = - props - |> FilterOverrides findFlag - ((fun (pinfo: PropInfo) -> pinfo.IsVirtualProperty), - (fun pinfo -> pinfo.IsNewSlot), - (fun pinfo -> pinfo.IsDefiniteFSharpOverride), - (fun _ -> false), - PropInfosEquivByNameAndSig EraseNone g amap m, - (fun pinfo -> pinfo.PropertyName)) - -/// Exclude methods from super types which have the same signature as a method in a more specific type. let ExcludeHiddenOfMethInfos g amap m (minfos: MethInfo list list) = - minfos - |> ExcludeItemsInSuperTypesBasedOnEquivTestWithItemsInSubTypes - (fun minfo -> minfo.LogicalName) - (fun m1 m2 -> - // only hide those truly from super classes - not (tyconRefEq g m1.DeclaringTyconRef m2.DeclaringTyconRef) && - MethInfosEquivByNameAndPartialSig EraseNone true g amap m m1 m2) - - |> List.concat + InfoReader.ExcludeHiddenOfMethInfos g amap m minfos -/// Exclude properties from super types which have the same name as a property in a more specific type. let ExcludeHiddenOfPropInfos g amap m pinfos = - pinfos - |> ExcludeItemsInSuperTypesBasedOnEquivTestWithItemsInSubTypes (fun (pinfo: PropInfo) -> pinfo.PropertyName) (PropInfosEquivByNameAndPartialSig EraseNone g amap m) - |> List.concat + InfoReader.ExcludeHiddenOfPropInfos g amap m pinfos -/// Get the sets of intrinsic methods in the hierarchy (not including extension methods) let GetIntrinsicMethInfoSetsOfType (infoReader:InfoReader) optFilter ad allowMultiIntfInst findFlag m ty = - infoReader.GetRawIntrinsicMethodSetsOfType(optFilter, ad, allowMultiIntfInst, m, ty) - |> FilterOverridesOfMethInfos findFlag infoReader.g infoReader.amap m + infoReader.GetIntrinsicMethInfoSetsOfType optFilter ad allowMultiIntfInst findFlag m ty -/// Get the sets intrinsic properties in the hierarchy (not including extension properties) let GetIntrinsicPropInfoSetsOfType (infoReader:InfoReader) optFilter ad allowMultiIntfInst findFlag m ty = - infoReader.GetRawIntrinsicPropertySetsOfType(optFilter, ad, allowMultiIntfInst, m, ty) - |> FilterOverridesOfPropInfos findFlag infoReader.g infoReader.amap m + infoReader.GetIntrinsicPropInfoSetsOfType optFilter ad allowMultiIntfInst findFlag m ty -/// Get the flattened list of intrinsic methods in the hierarchy -let GetIntrinsicMethInfosOfType infoReader optFilter ad allowMultiIntfInst findFlag m ty = - GetIntrinsicMethInfoSetsOfType infoReader optFilter ad allowMultiIntfInst findFlag m ty |> List.concat +let GetIntrinsicMethInfosOfType (infoReader: InfoReader) optFilter ad allowMultiIntfInst findFlag m ty = + infoReader.GetIntrinsicMethInfosOfType optFilter ad allowMultiIntfInst findFlag m ty -/// Get the flattened list of intrinsic properties in the hierarchy -let GetIntrinsicPropInfosOfType infoReader optFilter ad allowMultiIntfInst findFlag m ty = - GetIntrinsicPropInfoSetsOfType infoReader optFilter ad allowMultiIntfInst findFlag m ty |> List.concat +let GetIntrinsicPropInfosOfType (infoReader: InfoReader) optFilter ad allowMultiIntfInst findFlag m ty = + infoReader.GetIntrinsicPropInfosOfType optFilter ad allowMultiIntfInst findFlag m ty -/// Perform type-directed name resolution of a particular named member in an F# type let TryFindIntrinsicNamedItemOfType (infoReader: InfoReader) (nm, ad) findFlag m ty = - match infoReader.TryFindNamedItemOfType(nm, ad, m, ty) with - | Some item -> - match item with - | PropertyItem psets -> Some(PropertyItem (psets |> FilterOverridesOfPropInfos findFlag infoReader.g infoReader.amap m)) - | MethodItem msets -> Some(MethodItem (msets |> FilterOverridesOfMethInfos findFlag infoReader.g infoReader.amap m)) - | _ -> Some(item) - | None -> None - -/// Try to detect the existence of a method on a type. -/// Used for -/// -- getting the GetEnumerator, get_Current, MoveNext methods for enumerable types -/// -- getting the Dispose method when resolving the 'use' construct -/// -- getting the various methods used to desugar the computation expression syntax -let TryFindIntrinsicMethInfo infoReader m ad nm ty = - GetIntrinsicMethInfosOfType infoReader (Some nm) ad AllowMultiIntfInstantiations.Yes IgnoreOverrides m ty - -/// Try to find a particular named property on a type. Only used to ensure that local 'let' definitions and property names -/// are distinct, a somewhat adhoc check in tc.fs. -let TryFindPropInfo infoReader m ad nm ty = - GetIntrinsicPropInfosOfType infoReader (Some nm) ad AllowMultiIntfInstantiations.Yes IgnoreOverrides m ty + infoReader.TryFindIntrinsicNamedItemOfType (nm, ad) findFlag m ty + +let TryFindIntrinsicMethInfo (infoReader: InfoReader) m ad nm ty = + infoReader.TryFindIntrinsicMethInfo m ad nm ty + +let TryFindIntrinsicPropInfo (infoReader: InfoReader) m ad nm ty = + infoReader.TryFindIntrinsicPropInfo m ad nm ty /// Get a set of most specific override methods. let GetIntrinisicMostSpecificOverrideMethInfoSetsOfType (infoReader: InfoReader) m ty = diff --git a/src/fsharp/InfoReader.fsi b/src/fsharp/InfoReader.fsi index d8606880cec..3247ed7ac9e 100644 --- a/src/fsharp/InfoReader.fsi +++ b/src/fsharp/InfoReader.fsi @@ -52,6 +52,15 @@ type HierarchyItem = | EventItem of EventInfo list | ILFieldItem of ILFieldInfo list +/// Indicates if we prefer overrides or abstract slots. +type FindMemberFlag = + /// Prefer items toward the top of the hierarchy, which we do if the items are virtual + /// but not when resolving base calls. + | IgnoreOverrides + + /// Get overrides instead of abstract slots when measuring whether a class/interface implements all its required slots. + | PreferOverrides + /// An InfoReader is an object to help us read and cache infos. /// We create one of these for each file we typecheck. type InfoReader = @@ -86,6 +95,30 @@ type InfoReader = member amap: ImportMap member g: TcGlobals + /// Exclude methods from super types which have the same signature as a method in a more specific type. + static member ExcludeHiddenOfMethInfos: g:TcGlobals -> amap:ImportMap -> m:range -> minfos:MethInfo list list -> MethInfo list + + /// Exclude properties from super types which have the same name as a property in a more specific type. + static member ExcludeHiddenOfPropInfos: g:TcGlobals -> amap:ImportMap -> m:range -> pinfos:PropInfo list list -> PropInfo list + + /// Get the sets of intrinsic methods in the hierarchy (not including extension methods) + member GetIntrinsicMethInfoSetsOfType: optFilter:string option -> ad:AccessorDomain -> allowMultiIntfInst:AllowMultiIntfInstantiations -> findFlag:FindMemberFlag -> m:range -> ty:TType -> MethInfo list list + + /// Get the sets intrinsic properties in the hierarchy (not including extension properties) + member GetIntrinsicPropInfoSetsOfType: optFilter:string option -> ad:AccessorDomain -> allowMultiIntfInst:AllowMultiIntfInstantiations -> findFlag:FindMemberFlag -> m:range -> ty:TType -> PropInfo list list + + /// Get the flattened list of intrinsic methods in the hierarchy + member GetIntrinsicMethInfosOfType: optFilter:string option -> ad:AccessorDomain -> allowMultiIntfInst:AllowMultiIntfInstantiations -> findFlag:FindMemberFlag -> m:range -> ty:TType -> MethInfo list + + /// Get the flattened list of intrinsic properties in the hierarchy + member GetIntrinsicPropInfosOfType: optFilter:string option -> ad:AccessorDomain -> allowMultiIntfInst:AllowMultiIntfInstantiations -> findFlag:FindMemberFlag -> m:range -> ty:TType -> PropInfo list + + /// Perform type-directed name resolution of a particular named member in an F# type + member TryFindIntrinsicNamedItemOfType: nm:string * ad:AccessorDomain -> findFlag:FindMemberFlag -> m:range -> ty:TType -> HierarchyItem option + + /// Find the op_Implicit for a type + member FindImplicitConversions: m: range -> ad: AccessorDomain -> ty: TType -> MethInfo list + val checkLanguageFeatureRuntimeError: infoReader:InfoReader -> langFeature:Features.LanguageFeature -> m:range -> unit val checkLanguageFeatureRuntimeErrorRecover: infoReader:InfoReader -> langFeature:Features.LanguageFeature -> m:range -> unit @@ -95,15 +128,6 @@ val tryLanguageFeatureRuntimeErrorRecover: infoReader:InfoReader -> langFeature: /// Get the declared constructors of any F# type val GetIntrinsicConstructorInfosOfType: infoReader:InfoReader -> m:range -> ty:TType -> MethInfo list -/// Indicates if we prefer overrides or abstract slots. -type FindMemberFlag = - /// Prefer items toward the top of the hierarchy, which we do if the items are virtual - /// but not when resolving base calls. - | IgnoreOverrides - - /// Get overrides instead of abstract slots when measuring whether a class/interface implements all its required slots. - | PreferOverrides - /// Exclude methods from super types which have the same signature as a method in a more specific type. val ExcludeHiddenOfMethInfos: g:TcGlobals -> amap:ImportMap -> m:range -> minfos:MethInfo list list -> MethInfo list @@ -130,7 +154,7 @@ val TryFindIntrinsicMethInfo: infoReader:InfoReader -> m:range -> ad:AccessorDom /// Try to find a particular named property on a type. Only used to ensure that local 'let' definitions and property names /// are distinct, a somewhat adhoc check in tc.fs. -val TryFindPropInfo: infoReader:InfoReader -> m:range -> ad:AccessorDomain -> nm:string -> ty:TType -> PropInfo list +val TryFindIntrinsicPropInfo: infoReader:InfoReader -> m:range -> ad:AccessorDomain -> nm:string -> ty:TType -> PropInfo list /// Get a set of most specific override methods. val GetIntrinisicMostSpecificOverrideMethInfoSetsOfType: infoReader:InfoReader -> m:range -> ty:TType -> NameMultiMap diff --git a/src/fsharp/LanguageFeatures.fs b/src/fsharp/LanguageFeatures.fs index d49564500ea..421885db620 100644 --- a/src/fsharp/LanguageFeatures.fs +++ b/src/fsharp/LanguageFeatures.fs @@ -32,6 +32,7 @@ type LanguageFeature = | NullableOptionalInterop | DefaultInterfaceMemberConsumption | WitnessPassing + | AdditionalTypeDirectedConversions | InterfacesWithMultipleGenericInstantiation | StringInterpolation | OverloadsForCustomOperations @@ -79,6 +80,7 @@ type LanguageVersion (specifiedVersionAsString) = LanguageFeature.StringInterpolation, languageVersion50 // F# preview + LanguageFeature.AdditionalTypeDirectedConversions, previewVersion LanguageFeature.RelaxWhitespace2, previewVersion LanguageFeature.OverloadsForCustomOperations, previewVersion LanguageFeature.ExpandedMeasurables, previewVersion @@ -160,6 +162,7 @@ type LanguageVersion (specifiedVersionAsString) = | LanguageFeature.NullableOptionalInterop -> FSComp.SR.featureNullableOptionalInterop() | LanguageFeature.DefaultInterfaceMemberConsumption -> FSComp.SR.featureDefaultInterfaceMemberConsumption() | LanguageFeature.WitnessPassing -> FSComp.SR.featureWitnessPassing() + | LanguageFeature.AdditionalTypeDirectedConversions -> FSComp.SR.featureAdditionalImplicitConversions() | LanguageFeature.InterfacesWithMultipleGenericInstantiation -> FSComp.SR.featureInterfacesWithMultipleGenericInstantiation() | LanguageFeature.StringInterpolation -> FSComp.SR.featureStringInterpolation() | LanguageFeature.OverloadsForCustomOperations -> FSComp.SR.featureOverloadsForCustomOperations() diff --git a/src/fsharp/LanguageFeatures.fsi b/src/fsharp/LanguageFeatures.fsi index 060b6985298..6ca6693ce27 100644 --- a/src/fsharp/LanguageFeatures.fsi +++ b/src/fsharp/LanguageFeatures.fsi @@ -22,6 +22,7 @@ type LanguageFeature = | NullableOptionalInterop | DefaultInterfaceMemberConsumption | WitnessPassing + | AdditionalTypeDirectedConversions | InterfacesWithMultipleGenericInstantiation | StringInterpolation | OverloadsForCustomOperations diff --git a/src/fsharp/MethodCalls.fs b/src/fsharp/MethodCalls.fs index d276b174145..542bc35e510 100644 --- a/src/fsharp/MethodCalls.fs +++ b/src/fsharp/MethodCalls.fs @@ -137,64 +137,204 @@ type CallerArgs<'T> = // Callsite conversions //------------------------------------------------------------------------- -// If the called method argument is a delegate type, and the caller is known to be a function type, then the caller may provide a function -// If the called method argument is an Expression type, and the caller is known to be a function type, then the caller may provide a T -// If the called method argument is an [] Quotations.Expr, and the caller is not known to be a quoted expression type, then the caller may provide a T -let AdjustCalledArgTypeForLinqExpressionsAndAutoQuote (infoReader: InfoReader) callerArgTy (calledArg: CalledArg) m = +let AdjustDelegateTy (infoReader: InfoReader) actualTy reqdTy m = let g = infoReader.g - let calledArgTy = calledArg.CalledArgumentType + let (SigOfFunctionForDelegate(_, delArgTys, _, fty)) = GetSigOfFunctionForDelegate infoReader reqdTy m AccessibleFromSomewhere + let delArgTys = if isNil delArgTys then [g.unit_ty] else delArgTys + if (fst (stripFunTy g actualTy)).Length = delArgTys.Length then + fty + else + reqdTy - let adjustDelegateTy calledTy = - let (SigOfFunctionForDelegate(_, delArgTys, _, fty)) = GetSigOfFunctionForDelegate infoReader calledTy m AccessibleFromSomewhere - let delArgTys = if isNil delArgTys then [g.unit_ty] else delArgTys - if (fst (stripFunTy g callerArgTy)).Length = delArgTys.Length then - fty - else - calledArgTy - if isDelegateTy g calledArgTy && isFunTy g callerArgTy then - adjustDelegateTy calledArgTy +// Adhoc based on op_Implicit +// +// NOTE: +// no generic method op_Implicit as yet +// +// Search for an adhoc conversion based on op_Implicit, optionally returing a new equational type constraint to +// eliminate articifical constrained type variables. +// +// Allow adhoc for X --> Y where there is an op_Implicit from X to Y, and there is +// no feasible subtype relationship between X and Y. +// +// Also allow adhoc for X --> ? where the ? is a type inference variable constrained +// by a coercion constraint to Y for which there is an op_Implicit from X to Y, and there is +// no feasible subtype relationship between X and Y. +// +// Implicit conversions are only activated if the types precisely match based on known type information +// at the point of resolution. For example +// let f (x: 'T) : Nullable<'T> = x +// is enough, whereas +// let f (x: 'T) : Nullable<_> = x +// let f x : Nullable<'T> = x +// are not enough to activate. + +let TryFindRelevantImplicitConversion (infoReader: InfoReader) ad reqdTy actualTy m = + let g = infoReader.g + let amap = infoReader.amap + if g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions then + + // shortcut + if typeEquiv g reqdTy actualTy then None else + let reqdTy2 = + if isTyparTy g reqdTy then + let tp = destTyparTy g reqdTy + match tp.Constraints |> List.choose (function TyparConstraint.CoercesTo (c, _) -> Some c | _ -> None) with + | [reqdTy2] when tp.Rigidity = TyparRigidity.Flexible -> reqdTy2 + | _ -> reqdTy + else reqdTy + + // Implicit conversions only activate if a precise implicit conversion exists and: + // 1. no feasible subtype relationship between X and Y (an approximation), OR + // 2. T --> some-type-containing-precisely-T + // Note that even for (2) implicit conversions are still only activated if the + // types *precisely* and *completely* match based on *known* type information at the point of resolution. + + if not (isTyparTy g reqdTy2) && + (not (TypeFeasiblySubsumesType 0 g amap m reqdTy2 CanCoerce actualTy) || + isTyparTy g actualTy && (let ftyvs = freeInType CollectAll reqdTy2 in ftyvs.FreeTypars.Contains(destTyparTy g actualTy))) then - elif isLinqExpressionTy g calledArgTy && isFunTy g callerArgTy then - let calledArgTyNoExpr = destLinqExpressionTy g calledArgTy - if isDelegateTy g calledArgTyNoExpr then - adjustDelegateTy calledArgTyNoExpr + let implicits = + infoReader.FindImplicitConversions m ad actualTy @ + infoReader.FindImplicitConversions m ad reqdTy2 + + let implicits = + implicits |> List.filter (fun minfo -> + not minfo.IsInstance && + minfo.FormalMethodTyparInst.IsEmpty && + (match minfo.GetParamTypes(amap, m, []) with + | [[a]] -> typeEquiv g a actualTy + | _ -> false) && + (let rty = minfo.GetFSharpReturnTy(amap, m, []) + typeEquiv g rty reqdTy2) + ) + + match implicits with + | [minfo] -> + Some (minfo, (reqdTy, reqdTy2, ignore)) + | minfo :: _ -> + Some (minfo, (reqdTy, reqdTy2, fun denv -> + let reqdTy2Text, actualTyText, _cxs = NicePrint.minimalStringsOfTwoTypes denv reqdTy2 actualTy + let implicitsText = NicePrint.multiLineStringOfMethInfos infoReader m denv implicits + errorR(Error(FSComp.SR.tcAmbiguousImplicitConversion(actualTyText, reqdTy2Text, implicitsText), m)))) + | _ -> None else - calledArgTy + None + else + None + +[] +type TypeDirectedConversion = + | BuiltIn + | Implicit of MethInfo + +[] +type TypeDirectedConversionUsed = + | Yes of (DisplayEnv -> exn) + | No + static member Combine a b = + match a with + | Yes _ -> a + | No -> b - elif calledArg.ReflArgInfo.AutoQuote && isQuotedExprTy g calledArgTy && not (isQuotedExprTy g callerArgTy) then - destQuotedExprTy g calledArgTy +let MapCombineTDCD mapper xs = + MapReduceD mapper TypeDirectedConversionUsed.No TypeDirectedConversionUsed.Combine xs - else calledArgTy +let MapCombineTDC2D mapper xs ys = + MapReduce2D mapper TypeDirectedConversionUsed.No TypeDirectedConversionUsed.Combine xs ys + +let rec AdjustRequiredTypeForTypeDirectedConversions (infoReader: InfoReader) ad isMethodArg isConstraint (reqdTy: TType) actualTy m = + let g = infoReader.g + + let warn info denv = + let reqdTyText, actualTyText, _cxs = NicePrint.minimalStringsOfTwoTypes denv reqdTy actualTy + match info with + | TypeDirectedConversion.BuiltIn -> + Error(FSComp.SR.tcBuiltInImplicitConversionUsed(actualTyText, reqdTyText), m) + | TypeDirectedConversion.Implicit convMeth -> + let methText = NicePrint.stringOfMethInfo infoReader m denv convMeth + if isMethodArg then + Error(FSComp.SR.tcImplicitConversionUsedForMethodArg(methText, actualTyText, reqdTyText), m) + else + Error(FSComp.SR.tcImplicitConversionUsedForNonMethodArg(methText, actualTyText, reqdTyText), m) + + if isConstraint then + reqdTy, TypeDirectedConversionUsed.No, None + else + + // Delegate --> function + if isDelegateTy g reqdTy && isFunTy g actualTy then + AdjustDelegateTy infoReader actualTy reqdTy m, TypeDirectedConversionUsed.No, None + + // (T -> U) --> Expression U> LINQ-style quotation + elif isLinqExpressionTy g reqdTy && isDelegateTy g (destLinqExpressionTy g reqdTy) && isFunTy g actualTy then + let delegateTy = destLinqExpressionTy g reqdTy + AdjustRequiredTypeForTypeDirectedConversions infoReader ad isMethodArg isConstraint delegateTy actualTy m + + // Adhoc int32 --> int64 + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.int64_ty reqdTy && typeEquiv g g.int32_ty actualTy then + g.int32_ty, TypeDirectedConversionUsed.Yes(warn TypeDirectedConversion.BuiltIn), None + + // Adhoc int32 --> nativeint + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.nativeint_ty reqdTy && typeEquiv g g.int32_ty actualTy then + g.int32_ty, TypeDirectedConversionUsed.Yes(warn TypeDirectedConversion.BuiltIn), None + + // Adhoc int32 --> float64 + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.int32_ty actualTy then + g.int32_ty, TypeDirectedConversionUsed.Yes(warn TypeDirectedConversion.BuiltIn), None + + // Adhoc based on op_Implicit, perhaps returing a new equational type constraint to + // eliminate articifical constrained type variables. + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions then + match TryFindRelevantImplicitConversion infoReader ad reqdTy actualTy m with + | Some (minfo, eqn) -> actualTy, TypeDirectedConversionUsed.Yes(warn (TypeDirectedConversion.Implicit minfo)), Some eqn + | None -> reqdTy, TypeDirectedConversionUsed.No, None + + else reqdTy, TypeDirectedConversionUsed.No, None + +// If the called method argument is a delegate type, and the caller is known to be a function type, then the caller may provide a function +// If the called method argument is an Expression type, and the caller is known to be a function type, then the caller may provide a T +// If the called method argument is an [] Quotations.Expr, and the caller is not known to be a quoted expression type, then the caller may provide a T +let AdjustCalledArgTypeForTypeDirectedConversionsAndAutoQuote (infoReader: InfoReader) ad (callerArgTy: TType) calledArgTy (calledArg: CalledArg) m = + let g = infoReader.g + + if calledArg.ReflArgInfo.AutoQuote && isQuotedExprTy g calledArgTy && not (isQuotedExprTy g callerArgTy) then + destQuotedExprTy g calledArgTy, TypeDirectedConversionUsed.No, None + else + AdjustRequiredTypeForTypeDirectedConversions infoReader ad true false calledArgTy callerArgTy m /// Adjust the called argument type to take into account whether the caller's argument is CSharpMethod(?arg=Some(3)) or CSharpMethod(arg=1) -let AdjustCalledArgTypeForOptionals (g: TcGlobals) enforceNullableOptionalsKnownTypes (calledArg: CalledArg) calledArgTy (callerArg: CallerArg<_>) = +let AdjustCalledArgTypeForOptionals (infoReader: InfoReader) ad enforceNullableOptionalsKnownTypes (calledArg: CalledArg) calledArgTy (callerArg: CallerArg<_>) = + let g = infoReader.g + let m = callerArg.Range + let callerArgTy = callerArg.CallerArgumentType if callerArg.IsExplicitOptional then match calledArg.OptArgInfo with // CSharpMethod(?x = arg), optional C#-style argument, may have nullable type | CallerSide _ -> if g.langVersion.SupportsFeature LanguageFeature.NullableOptionalInterop then if isNullableTy g calledArgTy then - mkOptionTy g (destNullableTy g calledArgTy) + mkOptionTy g (destNullableTy g calledArgTy), TypeDirectedConversionUsed.No, None else - mkOptionTy g calledArgTy + mkOptionTy g calledArgTy, TypeDirectedConversionUsed.No, None else - calledArgTy + calledArgTy, TypeDirectedConversionUsed.No, None // FSharpMethod(?x = arg), optional F#-style argument | CalleeSide -> // In this case, the called argument will already have option type - calledArgTy + calledArgTy, TypeDirectedConversionUsed.No, None | NotOptional -> // This condition represents an error but the error is raised in later processing - calledArgTy + AdjustCalledArgTypeForTypeDirectedConversionsAndAutoQuote infoReader ad callerArgTy calledArgTy calledArg m else match calledArg.OptArgInfo with // CSharpMethod(x = arg), non-optional C#-style argument, may have type Nullable. | NotOptional when not (g.langVersion.SupportsFeature LanguageFeature.NullableOptionalInterop) -> - calledArgTy + AdjustCalledArgTypeForTypeDirectedConversionsAndAutoQuote infoReader ad callerArgTy calledArgTy calledArg m // The arg should have type ty. However for backwards compat, we also allow arg to have type Nullable | NotOptional @@ -202,35 +342,41 @@ let AdjustCalledArgTypeForOptionals (g: TcGlobals) enforceNullableOptionalsKnown | CallerSide _ -> if isNullableTy g calledArgTy && g.langVersion.SupportsFeature LanguageFeature.NullableOptionalInterop then // If inference has worked out it's a nullable then use this - if isNullableTy g callerArg.CallerArgumentType then - calledArgTy + if isNullableTy g callerArgTy then + calledArgTy, TypeDirectedConversionUsed.No, None + // If inference has worked out it's a struct (e.g. an int) then use this - elif isStructTy g callerArg.CallerArgumentType then - destNullableTy g calledArgTy + elif isStructTy g callerArgTy then + let calledArgTy2 = destNullableTy g calledArgTy + AdjustRequiredTypeForTypeDirectedConversions infoReader ad true false calledArgTy2 callerArgTy m + // If neither and we are at the end of overload resolution then use the Nullable elif enforceNullableOptionalsKnownTypes then - calledArgTy + calledArgTy, TypeDirectedConversionUsed.No, None + // If at the beginning of inference then use a type variable. else match calledArg.OptArgInfo with // If inference has not solved the kind of Nullable on the called arg and is not optional then use this. | NotOptional when isTyparTy g (destNullableTy g calledArgTy) -> - calledArgTy + calledArgTy, TypeDirectedConversionUsed.No, None | _ -> let compgenId = mkSynId range0 unassignedTyparName - mkTyparTy (Construct.NewTypar (TyparKind.Type, TyparRigidity.Flexible, SynTypar(compgenId, TyparStaticReq.None, true), false, TyparDynamicReq.No, [], false, false)) + let tp = mkTyparTy (Construct.NewTypar (TyparKind.Type, TyparRigidity.Flexible, SynTypar(compgenId, TyparStaticReq.None, true), false, TyparDynamicReq.No, [], false, false)) + tp, TypeDirectedConversionUsed.No, None else - calledArgTy + AdjustCalledArgTypeForTypeDirectedConversionsAndAutoQuote infoReader ad callerArgTy calledArgTy calledArg m // FSharpMethod(x = arg), optional F#-style argument, should have option type | CalleeSide -> - if isOptionTy g calledArgTy then - destOptionTy g calledArgTy - else - calledArgTy + let calledArgTy2 = + if isOptionTy g calledArgTy then + destOptionTy g calledArgTy + else + calledArgTy + AdjustCalledArgTypeForTypeDirectedConversionsAndAutoQuote infoReader ad callerArgTy calledArgTy2 calledArg m -// F# supports three adhoc conversions at method callsites (note C# supports more, though ones -// such as implicit conversions interact badly with type inference). +// F# supports adhoc conversions at some specific points // // 1. The use of "(fun x y -> ...)" when a delegate it expected. This is not part of // the ":>" coercion relationship or inference constraint problem as @@ -247,15 +393,16 @@ let AdjustCalledArgTypeForOptionals (g: TcGlobals) enforceNullableOptionalsKnown // and record the presence of the syntax "&e" in the pre-inferred actual type for the method argument. // The function AdjustCalledArgType detects this and refuses to apply the default byref-to-ref transformation. // +// 4. Other type directed conversions in 'AdjustRequiredTypeForTypeDirectedConversions' +// // The function AdjustCalledArgType also adjusts for optional arguments. -let AdjustCalledArgType (infoReader: InfoReader) isConstraint enforceNullableOptionalsKnownTypes (calledArg: CalledArg) (callerArg: CallerArg<_>) = +let AdjustCalledArgType (infoReader: InfoReader) ad isConstraint enforceNullableOptionalsKnownTypes (calledArg: CalledArg) (callerArg: CallerArg<_>) = let g = infoReader.g - let m = callerArg.Range // #424218 - when overload resolution is part of constraint solving - do not perform type-directed conversions let calledArgTy = calledArg.CalledArgumentType let callerArgTy = callerArg.CallerArgumentType if isConstraint then - calledArgTy + calledArgTy, TypeDirectedConversionUsed.No, None else // If the called method argument is an inref type, then the caller may provide a byref or value @@ -266,20 +413,18 @@ let AdjustCalledArgType (infoReader: InfoReader) isConstraint enforceNullableOpt else destByrefTy g calledArgTy #else - calledArgTy + calledArgTy, TypeDirectedConversionUsed.No, None #endif // If the called method argument is a (non inref) byref type, then the caller may provide a byref or ref. elif isByrefTy g calledArgTy then if isByrefTy g callerArgTy then - calledArgTy + calledArgTy, TypeDirectedConversionUsed.No, None else - mkRefCellTy g (destByrefTy g calledArgTy) + mkRefCellTy g (destByrefTy g calledArgTy), TypeDirectedConversionUsed.No, None else - let calledArgTy2 = AdjustCalledArgTypeForLinqExpressionsAndAutoQuote infoReader callerArgTy calledArg m - let calledArgTy3 = AdjustCalledArgTypeForOptionals g enforceNullableOptionalsKnownTypes calledArg calledArgTy2 callerArg - calledArgTy3 + AdjustCalledArgTypeForOptionals infoReader ad enforceNullableOptionalsKnownTypes calledArg calledArgTy callerArg //------------------------------------------------------------------------- // CalledMeth @@ -356,7 +501,7 @@ type CalledMeth<'T> tyargsOpt : TType option) = let g = infoReader.g - let methodRetTy = minfo.GetFSharpReturnTy(infoReader.amap, m, calledTyArgs) + let methodRetTy = if minfo.IsConstructor then minfo.ApparentEnclosingType else minfo.GetFSharpReturnTy(infoReader.amap, m, calledTyArgs) let fullCurriedCalledArgs = MakeCalledArgs infoReader.amap m minfo calledTyArgs do assert (fullCurriedCalledArgs.Length = fullCurriedCalledArgs.Length) @@ -427,7 +572,7 @@ type CalledMeth<'T> [] let assignedNamedProps, unassignedNamedItems = - let returnedObjTy = if minfo.IsConstructor then minfo.ApparentEnclosingType else methodRetTy + let returnedObjTy = methodRetTy unassignedNamedItems |> List.splitChoose (fun (CallerNamedArg(id, e) as arg) -> let nm = id.idText let pinfos = GetIntrinsicPropInfoSetsOfType infoReader (Some nm) ad AllowMultiIntfInstantiations.Yes IgnoreOverrides id.idRange returnedObjTy @@ -508,8 +653,7 @@ type CalledMeth<'T> /// The return type after implicit deference of byref returns is taken into account member x.CalledReturnTypeAfterByrefDeref = - let retTy = methodRetTy - if isByrefTy g retTy then destByrefTy g retTy else retTy + if isByrefTy g methodRetTy then destByrefTy g methodRetTy else methodRetTy /// Return type after tupling of out args is taken into account member x.CalledReturnTypeAfterOutArgTupling = @@ -630,7 +774,7 @@ let InferLambdaArgsForLambdaPropagation origRhsExpr = | _ -> 0 loop origRhsExpr -let ExamineArgumentForLambdaPropagation (infoReader: InfoReader) (arg: AssignedCalledArg) = +let ExamineArgumentForLambdaPropagation (infoReader: InfoReader) ad (arg: AssignedCalledArg) = let g = infoReader.g // Find the explicit lambda arguments of the caller. Ignore parentheses. @@ -638,7 +782,7 @@ let ExamineArgumentForLambdaPropagation (infoReader: InfoReader) (arg: AssignedC let countOfCallerLambdaArg = InferLambdaArgsForLambdaPropagation argExpr // Adjust for Expression<_>, Func<_, _>, ... - let adjustedCalledArgTy = AdjustCalledArgType infoReader false false arg.CalledArg arg.CallerArg + let adjustedCalledArgTy, _, _ = AdjustCalledArgType infoReader ad false false arg.CalledArg arg.CallerArg if countOfCallerLambdaArg > 0 then // Decompose the explicit function type of the target let calledLambdaArgTys, _calledLambdaRetTy = stripFunTy g adjustedCalledArgTy @@ -656,9 +800,9 @@ let ExamineArgumentForLambdaPropagation (infoReader: InfoReader) (arg: AssignedC CalledArgMatchesType(adjustedCalledArgTy) -let ExamineMethodForLambdaPropagation (x: CalledMeth) = - let unnamedInfo = x.AssignedUnnamedArgs |> List.mapSquared (ExamineArgumentForLambdaPropagation x.infoReader) - let namedInfo = x.AssignedNamedArgs |> List.mapSquared (fun arg -> (arg.NamedArgIdOpt.Value, ExamineArgumentForLambdaPropagation x.infoReader arg)) +let ExamineMethodForLambdaPropagation (x: CalledMeth) ad = + let unnamedInfo = x.AssignedUnnamedArgs |> List.mapSquared (ExamineArgumentForLambdaPropagation x.infoReader ad) + let namedInfo = x.AssignedNamedArgs |> List.mapSquared (fun arg -> (arg.NamedArgIdOpt.Value, ExamineArgumentForLambdaPropagation x.infoReader ad arg)) if unnamedInfo |> List.existsSquared (function CallerLambdaHasArgTypes _ -> true | _ -> false) || namedInfo |> List.existsSquared (function _, CallerLambdaHasArgTypes _ -> true | _ -> false) then Some (unnamedInfo, namedInfo) @@ -958,6 +1102,56 @@ let BuildMethodCall tcVal g amap isMutable m isProp minfo valUseFlags minst objA errorR(Error(FSComp.SR.tcDefaultStructConstructorCall(), m)) mkDefault (m, ty), ty) +let ILFieldStaticChecks g amap infoReader ad m (finfo : ILFieldInfo) = + CheckILFieldInfoAccessible g amap m ad finfo + if not finfo.IsStatic then error (Error (FSComp.SR.tcFieldIsNotStatic(finfo.FieldName), m)) + + // Static IL interfaces fields are not supported in lower F# versions. + if isInterfaceTy g finfo.ApparentEnclosingType then + checkLanguageFeatureRuntimeErrorRecover infoReader LanguageFeature.DefaultInterfaceMemberConsumption m + checkLanguageFeatureErrorRecover g.langVersion LanguageFeature.DefaultInterfaceMemberConsumption m + + CheckILFieldAttributes g finfo m + +let ILFieldInstanceChecks g amap ad m (finfo : ILFieldInfo) = + if finfo.IsStatic then error (Error (FSComp.SR.tcStaticFieldUsedWhenInstanceFieldExpected(), m)) + CheckILFieldInfoAccessible g amap m ad finfo + CheckILFieldAttributes g finfo m + +let MethInfoChecks g amap isInstance tyargsOpt objArgs ad m (minfo: MethInfo) = + if minfo.IsInstance <> isInstance then + if isInstance then + error (Error (FSComp.SR.csMethodIsNotAnInstanceMethod(minfo.LogicalName), m)) + else + error (Error (FSComp.SR.csMethodIsNotAStaticMethod(minfo.LogicalName), m)) + + // keep the original accessibility domain to determine type accessibility + let adOriginal = ad + // Eliminate the 'protected' portion of the accessibility domain for instance accesses + let ad = + match objArgs, ad with + | [objArg], AccessibleFrom(paths, Some tcref) -> + let objArgTy = tyOfExpr g objArg + let ty = generalizedTyconRef tcref + // We get to keep our rights if the type we're in subsumes the object argument type + if TypeFeasiblySubsumesType 0 g amap m ty CanCoerce objArgTy then + ad + // We get to keep our rights if this is a base call + elif IsBaseCall objArgs then + ad + else + AccessibleFrom(paths, None) + | _ -> ad + + if not (IsTypeAndMethInfoAccessible amap m adOriginal ad minfo) then + error (Error (FSComp.SR.tcMethodNotAccessible(minfo.LogicalName), m)) + + if isAnyTupleTy g minfo.ApparentEnclosingType && not minfo.IsExtensionMember && + (minfo.LogicalName.StartsWithOrdinal("get_Item") || minfo.LogicalName.StartsWithOrdinal("get_Rest")) then + warning (Error (FSComp.SR.tcTupleMemberNotNormallyUsed(), m)) + + CheckMethInfoAttributes g m tyargsOpt minfo |> CommitOperationResult + //------------------------------------------------------------------------- // Adjust caller arguments as part of building a method call //------------------------------------------------------------------------- @@ -1013,7 +1207,40 @@ let CoerceFromFSharpFuncToDelegate g amap infoReader ad callerArgTy m callerArgE BuildNewDelegateExpr (None, g, amap, delegateTy, invokeMethInfo, delArgTys, callerArgExpr, callerArgTy, m) // Handle adhoc argument conversions -let AdjustCallerArgExprForCoercions (g: TcGlobals) amap infoReader ad isOutArg calledArgTy (reflArgInfo: ReflectedArgInfo) callerArgTy m callerArgExpr = +let rec AdjustExprForTypeDirectedConversions tcVal (g: TcGlobals) amap infoReader ad reqdTy actualTy m expr = + if isDelegateTy g reqdTy && isFunTy g actualTy then + CoerceFromFSharpFuncToDelegate g amap infoReader ad actualTy m expr reqdTy + + elif isLinqExpressionTy g reqdTy && isDelegateTy g (destLinqExpressionTy g reqdTy) && isFunTy g actualTy then + let delegateTy = destLinqExpressionTy g reqdTy + let expr2 = AdjustExprForTypeDirectedConversions tcVal g amap infoReader ad delegateTy actualTy m expr + mkCallQuoteToLinqLambdaExpression g m delegateTy (Expr.Quote (expr2, ref None, false, m, mkQuotedExprTy g delegateTy)) + + // Adhoc int32 --> int64 + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.int64_ty reqdTy && typeEquiv g g.int32_ty actualTy then + mkCallToInt64Operator g m actualTy expr + + // Adhoc int32 --> nativeint + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.nativeint_ty reqdTy && typeEquiv g g.int32_ty actualTy then + mkCallToIntPtrOperator g m actualTy expr + + // Adhoc int32 --> float64 + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.int32_ty actualTy then + mkCallToDoubleOperator g m actualTy expr + + else + match TryFindRelevantImplicitConversion infoReader ad reqdTy actualTy m with + | Some (minfo, _) -> + MethInfoChecks g amap false None [] ad m minfo + let callExpr, _ = BuildMethodCall tcVal g amap Mutates.NeverMutates m false minfo ValUseFlag.NormalValUse [] [] [expr] + assert (let resTy = tyOfExpr g callExpr in typeEquiv g reqdTy resTy) + callExpr + | None -> mkCoerceIfNeeded g reqdTy actualTy expr + // TODO: consider Nullable + + +// Handle adhoc argument conversions +let AdjustCallerArgExpr tcVal (g: TcGlobals) amap infoReader ad isOutArg calledArgTy (reflArgInfo: ReflectedArgInfo) callerArgTy m callerArgExpr = if isByrefTy g calledArgTy && isRefCellTy g callerArgTy then None, Expr.Op (TOp.RefAddrGet false, [destRefCellTy g callerArgTy], [callerArgExpr], m) @@ -1023,14 +1250,6 @@ let AdjustCallerArgExprForCoercions (g: TcGlobals) amap infoReader ad isOutArg c Some wrap, callerArgExprAddress #endif - elif isDelegateTy g calledArgTy && isFunTy g callerArgTy then - None, CoerceFromFSharpFuncToDelegate g amap infoReader ad callerArgTy m callerArgExpr calledArgTy - - elif isLinqExpressionTy g calledArgTy && isDelegateTy g (destLinqExpressionTy g calledArgTy) && isFunTy g callerArgTy then - let delegateTy = destLinqExpressionTy g calledArgTy - let expr = CoerceFromFSharpFuncToDelegate g amap infoReader ad callerArgTy m callerArgExpr delegateTy - None, mkCallQuoteToLinqLambdaExpression g m delegateTy (Expr.Quote (expr, ref None, false, m, mkQuotedExprTy g delegateTy)) - // auto conversions to quotations (to match auto conversions to LINQ expressions) elif reflArgInfo.AutoQuote && isQuotedExprTy g calledArgTy && not (isQuotedExprTy g callerArgTy) then match reflArgInfo with @@ -1044,9 +1263,9 @@ let AdjustCallerArgExprForCoercions (g: TcGlobals) amap infoReader ad isOutArg c elif isOutArg then None, callerArgExpr - // Note: not all these casts are reported in quotations else - None, mkCoerceIfNeeded g calledArgTy callerArgTy callerArgExpr + let callerArgExpr2 = AdjustExprForTypeDirectedConversions tcVal g amap infoReader ad calledArgTy callerArgTy m callerArgExpr + None, callerArgExpr2 /// Some of the code below must allocate temporary variables or bind other variables to particular values. /// As usual we represent variable allocators by expr -> expr functions @@ -1165,11 +1384,14 @@ let MakeNullableExprIfNeeded (infoReader: InfoReader) calledArgTy callerArgTy ca MakeMethInfoCall amap m minfo [] [callerArgExprCoerced] // Adjust all the optional arguments, filling in values for defaults, -let AdjustCallerArgForOptional tcFieldInit eCallerMemberName (infoReader: InfoReader) (assignedArg: AssignedCalledArg<_>) = +let AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName (infoReader: InfoReader) ad (assignedArg: AssignedCalledArg<_>) = let g = infoReader.g + let amap = infoReader.amap let callerArg = assignedArg.CallerArg let (CallerArg(callerArgTy, m, isOptCallerArg, callerArgExpr)) = callerArg let calledArg = assignedArg.CalledArg + let isOutArg = calledArg.IsOutArg + let reflArgInfo = calledArg.ReflArgInfo let calledArgTy = calledArg.CalledArgumentType match calledArg.OptArgInfo with | NotOptional when not (g.langVersion.SupportsFeature LanguageFeature.NullableOptionalInterop) -> @@ -1193,7 +1415,12 @@ let AdjustCallerArgForOptional tcFieldInit eCallerMemberName (infoReader: InfoRe // T --> Nullable widening at callsites if isOptCallerArg then errorR(Error(FSComp.SR.tcFormalArgumentIsNotOptional(), m)) if isNullableTy g calledArgTy then - MakeNullableExprIfNeeded infoReader calledArgTy callerArgTy callerArgExpr m + if isNullableTy g callerArgTy then + callerArgExpr + else + let calledNonOptTy = destNullableTy g calledArgTy + let _, callerArgExpr2 = AdjustCallerArgExpr tcVal g amap infoReader ad isOutArg calledNonOptTy reflArgInfo callerArgTy m callerArgExpr + MakeNullableExprIfNeeded infoReader calledArgTy callerArgTy callerArgExpr2 m else failwith "unreachable" // see case above @@ -1216,24 +1443,30 @@ let AdjustCallerArgForOptional tcFieldInit eCallerMemberName (infoReader: InfoRe callerArgExpr else if isNullableTy g calledArgTy then - // CSharpMethod(x=b) when 'x' has nullable type - // CSharpMethod(x=b) when both 'x' and 'b' have nullable type --> CSharpMethod(x=b) - // CSharpMethod(x=b) when 'x' has nullable type and 'b' does not --> CSharpMethod(x=Nullable(b)) - MakeNullableExprIfNeeded infoReader calledArgTy callerArgTy callerArgExpr m + if isNullableTy g callerArgTy then + // CSharpMethod(x=b) when 'x' has nullable type + // CSharpMethod(x=b) when both 'x' and 'b' have nullable type --> CSharpMethod(x=b) + callerArgExpr + else + // CSharpMethod(x=b) when 'x' has nullable type and 'b' does not --> CSharpMethod(x=Nullable(b)) + let calledNonOptTy = destNullableTy g calledArgTy + let _, callerArgExpr2 = AdjustCallerArgExpr tcVal g amap infoReader ad isOutArg calledNonOptTy reflArgInfo callerArgTy m callerArgExpr + MakeNullableExprIfNeeded infoReader calledArgTy callerArgTy callerArgExpr2 m else // CSharpMethod(x=b) --> CSharpMethod(?x=b) - callerArgExpr + let _, callerArgExpr2 = AdjustCallerArgExpr tcVal g amap infoReader ad isOutArg calledArgTy reflArgInfo callerArgTy m callerArgExpr + callerArgExpr2 | CalleeSide -> if isOptCallerArg then - // CSharpMethod(?x=b) --> CSharpMethod(?x=b) + // FSharpMethod(?x=b) --> FSharpMethod(?x=b) callerArgExpr else - // CSharpMethod(x=b) when CSharpMethod(A) --> CSharpMethod(?x=Some(b :> A)) + // FSharpMethod(x=b) when FSharpMethod(A) --> FSharpMethod(?x=Some(b :> A)) if isOptionTy g calledArgTy then let calledNonOptTy = destOptionTy g calledArgTy - let callerArgExprCoerced = mkCoerceIfNeeded g calledNonOptTy callerArgTy callerArgExpr - mkSome g calledNonOptTy callerArgExprCoerced m + let _, callerArgExpr2 = AdjustCallerArgExpr tcVal g amap infoReader ad isOutArg calledNonOptTy reflArgInfo callerArgTy m callerArgExpr + mkSome g calledNonOptTy callerArgExpr2 m else assert false callerArgExpr // defensive code - this case is unreachable @@ -1260,7 +1493,7 @@ let AdjustCallerArgForOptional tcFieldInit eCallerMemberName (infoReader: InfoRe // - VB also allows you to pass intrinsic values as optional values to parameters // typed as Object. What we do in this case is we box the intrinsic value." // -let AdjustCallerArgsForOptionals tcFieldInit eCallerMemberName (infoReader: InfoReader) (calledMeth: CalledMeth<_>) mItem mMethExpr = +let AdjustCallerArgsForOptionals tcVal tcFieldInit eCallerMemberName (infoReader: InfoReader) ad (calledMeth: CalledMeth<_>) mItem mMethExpr = let g = infoReader.g let assignedNamedArgs = calledMeth.ArgSets |> List.collect (fun argSet -> argSet.AssignedNamedArgs) @@ -1277,8 +1510,8 @@ let AdjustCallerArgsForOptionals tcFieldInit eCallerMemberName (infoReader: Info let preBinder2, arg = GetDefaultExpressionForOptionalArg tcFieldInit g calledArg eCallerMemberName mItem mMethExpr arg, (preBinder >> preBinder2)) - let adjustedNormalUnnamedArgs = List.map (AdjustCallerArgForOptional tcFieldInit eCallerMemberName infoReader) unnamedArgs - let adjustedAssignedNamedArgs = List.map (AdjustCallerArgForOptional tcFieldInit eCallerMemberName infoReader) assignedNamedArgs + let adjustedNormalUnnamedArgs = List.map (AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName infoReader ad) unnamedArgs + let adjustedAssignedNamedArgs = List.map (AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName infoReader ad) assignedNamedArgs optArgs, optArgPreBinder, adjustedNormalUnnamedArgs, adjustedAssignedNamedArgs @@ -1295,7 +1528,7 @@ let AdjustOutCallerArgs g (calledMeth: CalledMeth<_>) mMethExpr = |> List.unzip3 /// Adjust any '[]' arguments, converting to an array -let AdjustParamArrayCallerArgs g amap infoReader ad (calledMeth: CalledMeth<_>) mMethExpr = +let AdjustParamArrayCallerArgs tcVal g amap infoReader ad (calledMeth: CalledMeth<_>) mMethExpr = let argSets = calledMeth.ArgSets let paramArrayCallerArgs = argSets |> List.collect (fun argSet -> argSet.ParamArrayCallerArgs) @@ -1311,7 +1544,7 @@ let AdjustParamArrayCallerArgs g amap infoReader ad (calledMeth: CalledMeth<_>) paramArrayCallerArgs |> List.map (fun callerArg -> let (CallerArg(callerArgTy, m, isOutArg, callerArgExpr)) = callerArg - AdjustCallerArgExprForCoercions g amap infoReader ad isOutArg paramArrayCalledArgElementType paramArrayCalledArg.ReflArgInfo callerArgTy m callerArgExpr) + AdjustCallerArgExpr tcVal g amap infoReader ad isOutArg paramArrayCalledArgElementType paramArrayCalledArg.ReflArgInfo callerArgTy m callerArgExpr) |> List.unzip let paramArrayExpr = Expr.Op (TOp.Array, [paramArrayCalledArgElementType], paramArrayExprs, mMethExpr) @@ -1326,7 +1559,7 @@ let AdjustParamArrayCallerArgs g amap infoReader ad (calledMeth: CalledMeth<_>) /// Build the argument list for a method call. Adjust for param array, optional arguments, byref arguments and coercions. /// For example, if you pass an F# reference cell to a byref then we must get the address of the /// contents of the ref. Likewise lots of adjustments are made for optional arguments etc. -let AdjustCallerArgs tcFieldInit eCallerMemberName (infoReader: InfoReader) ad (calledMeth: CalledMeth<_>) objArgs lambdaVars mItem mMethExpr = +let AdjustCallerArgs tcVal tcFieldInit eCallerMemberName (infoReader: InfoReader) ad (calledMeth: CalledMeth<_>) objArgs lambdaVars mItem mMethExpr = let g = infoReader.g let amap = infoReader.amap let calledMethInfo = calledMeth.Method @@ -1345,10 +1578,10 @@ let AdjustCallerArgs tcFieldInit eCallerMemberName (infoReader: InfoReader) ad ( // Handle param array and optional arguments let paramArrayPreBinders, paramArrayArgs = - AdjustParamArrayCallerArgs g amap infoReader ad calledMeth mMethExpr + AdjustParamArrayCallerArgs tcVal g amap infoReader ad calledMeth mMethExpr let optArgs, optArgPreBinder, adjustedNormalUnnamedArgs, adjustedFinalAssignedNamedArgs = - AdjustCallerArgsForOptionals tcFieldInit eCallerMemberName infoReader calledMeth mItem mMethExpr + AdjustCallerArgsForOptionals tcVal tcFieldInit eCallerMemberName infoReader ad calledMeth mItem mMethExpr let outArgs, outArgExprs, outArgTmpBinds = AdjustOutCallerArgs g calledMeth mMethExpr @@ -1371,7 +1604,7 @@ let AdjustCallerArgs tcFieldInit eCallerMemberName (infoReader: InfoReader) ad ( let calledArgTy = assignedArg.CalledArg.CalledArgumentType let (CallerArg(callerArgTy, m, _, e)) = assignedArg.CallerArg - AdjustCallerArgExprForCoercions g amap infoReader ad isOutArg calledArgTy reflArgInfo callerArgTy m e) + AdjustCallerArgExpr tcVal g amap infoReader ad isOutArg calledArgTy reflArgInfo callerArgTy m e) |> List.unzip objArgPreBinder, objArgs, allArgsPreBinders, allArgs, allArgsCoerced, optArgPreBinder, paramArrayPreBinders, outArgExprs, outArgTmpBinds @@ -1748,56 +1981,6 @@ let RecdFieldInstanceChecks g amap ad m (rfinfo: RecdFieldInfo) = CheckRecdFieldInfoAttributes g rfinfo m |> CommitOperationResult CheckRecdFieldInfoAccessible amap m ad rfinfo -let ILFieldStaticChecks g amap infoReader ad m (finfo : ILFieldInfo) = - CheckILFieldInfoAccessible g amap m ad finfo - if not finfo.IsStatic then error (Error (FSComp.SR.tcFieldIsNotStatic(finfo.FieldName), m)) - - // Static IL interfaces fields are not supported in lower F# versions. - if isInterfaceTy g finfo.ApparentEnclosingType then - checkLanguageFeatureRuntimeErrorRecover infoReader LanguageFeature.DefaultInterfaceMemberConsumption m - checkLanguageFeatureErrorRecover g.langVersion LanguageFeature.DefaultInterfaceMemberConsumption m - - CheckILFieldAttributes g finfo m - -let ILFieldInstanceChecks g amap ad m (finfo : ILFieldInfo) = - if finfo.IsStatic then error (Error (FSComp.SR.tcStaticFieldUsedWhenInstanceFieldExpected(), m)) - CheckILFieldInfoAccessible g amap m ad finfo - CheckILFieldAttributes g finfo m - -let MethInfoChecks g amap isInstance tyargsOpt objArgs ad m (minfo: MethInfo) = - if minfo.IsInstance <> isInstance then - if isInstance then - error (Error (FSComp.SR.csMethodIsNotAnInstanceMethod(minfo.LogicalName), m)) - else - error (Error (FSComp.SR.csMethodIsNotAStaticMethod(minfo.LogicalName), m)) - - // keep the original accessibility domain to determine type accessibility - let adOriginal = ad - // Eliminate the 'protected' portion of the accessibility domain for instance accesses - let ad = - match objArgs, ad with - | [objArg], AccessibleFrom(paths, Some tcref) -> - let objArgTy = tyOfExpr g objArg - let ty = generalizedTyconRef tcref - // We get to keep our rights if the type we're in subsumes the object argument type - if TypeFeasiblySubsumesType 0 g amap m ty CanCoerce objArgTy then - ad - // We get to keep our rights if this is a base call - elif IsBaseCall objArgs then - ad - else - AccessibleFrom(paths, None) - | _ -> ad - - if not (IsTypeAndMethInfoAccessible amap m adOriginal ad minfo) then - error (Error (FSComp.SR.tcMethodNotAccessible(minfo.LogicalName), m)) - - if isAnyTupleTy g minfo.ApparentEnclosingType && not minfo.IsExtensionMember && - (minfo.LogicalName.StartsWithOrdinal("get_Item") || minfo.LogicalName.StartsWithOrdinal("get_Rest")) then - warning (Error (FSComp.SR.tcTupleMemberNotNormallyUsed(), m)) - - CheckMethInfoAttributes g m tyargsOpt minfo |> CommitOperationResult - exception FieldNotMutable of DisplayEnv * RecdFieldRef * range let CheckRecdFieldMutation m denv (rfinfo: RecdFieldInfo) = diff --git a/src/fsharp/MethodCalls.fsi b/src/fsharp/MethodCalls.fsi index 968ab700842..1624d0d9662 100644 --- a/src/fsharp/MethodCalls.fsi +++ b/src/fsharp/MethodCalls.fsi @@ -5,6 +5,7 @@ module internal FSharp.Compiler.MethodCalls open FSharp.Compiler open FSharp.Compiler.AccessibilityLogic +open FSharp.Compiler.ErrorLogger open FSharp.Compiler.Import open FSharp.Compiler.InfoReader open FSharp.Compiler.Infos @@ -13,6 +14,7 @@ open FSharp.Compiler.Syntax open FSharp.Compiler.Text open FSharp.Compiler.TcGlobals open FSharp.Compiler.TypedTree +open FSharp.Compiler.TypedTreeOps #if !NO_EXTENSIONTYPING open FSharp.Compiler.ExtensionTyping @@ -79,8 +81,11 @@ type AssignedItemSetter<'T> = type CallerNamedArg<'T> = | CallerNamedArg of Ident * CallerArg<'T> + member CallerArg: CallerArg<'T> + member Ident: Ident + member Name: string /// Represents the list of unnamed / named arguments at method call site @@ -90,13 +95,51 @@ type CallerNamedArg<'T> = type CallerArgs<'T> = { Unnamed: CallerArg<'T> list list Named: CallerNamedArg<'T> list list } + member ArgumentNamesAndTypes: (string option * TType) list + member CallerArgCounts: int * int + member CurriedCallerArgs: (CallerArg<'T> list * CallerNamedArg<'T> list) list + static member Empty: CallerArgs<'T> -/// F# supports some adhoc conversions at method callsites -val AdjustCalledArgType: infoReader:InfoReader -> isConstraint:bool -> enforceNullableOptionalsKnownTypes:bool -> calledArg:CalledArg -> callerArg:CallerArg<'a> -> TType +/// Indicates whether a type directed conversion (e.g. int32 to int64, or op_Implicit) +/// has been used in F# code +[] +type TypeDirectedConversionUsed = + | Yes of (DisplayEnv -> exn) + | No + static member Combine: TypeDirectedConversionUsed -> TypeDirectedConversionUsed -> TypeDirectedConversionUsed + +/// Performs a set of constraint solver operations returning TypeDirectedConversionUsed and +/// combines their results. +val MapCombineTDCD: mapper:('a -> OperationResult) -> xs:'a list -> OperationResult + +/// Performs a set of constraint solver operations returning TypeDirectedConversionUsed and +/// combines their results. +val MapCombineTDC2D: mapper:('a -> 'b -> OperationResult) -> xs:'a list -> ys:'b list -> OperationResult + +/// F# supports some adhoc conversions to make expression fit known overall type +val AdjustRequiredTypeForTypeDirectedConversions: + infoReader:InfoReader -> + ad: AccessorDomain -> + isMethodArg: bool -> + isConstraint: bool -> + reqdTy: TType -> + actualTy:TType -> + m: range + -> TType * TypeDirectedConversionUsed * (TType * TType * (DisplayEnv -> unit)) option + +/// F# supports some adhoc conversions to make expression fit known overall type +val AdjustCalledArgType: + infoReader:InfoReader -> + ad: AccessorDomain -> + isConstraint:bool -> + enforceNullableOptionalsKnownTypes:bool -> + calledArg:CalledArg -> + callerArg:CallerArg<'a> + -> TType * TypeDirectedConversionUsed * (TType * TType * (DisplayEnv -> unit)) option type CalledMethArgSet<'T> = { /// The called arguments corresponding to "unnamed" arguments @@ -141,13 +184,21 @@ type CalledMeth<'T> = allowParamArgs:bool * allowOutAndOptArgs:bool * tyargsOpt:TType option -> CalledMeth<'T> + static member GetMethod: x:CalledMeth<'T> -> MethInfo + member CalledObjArgTys: m:range -> TType list + member GetParamArrayElementType: unit -> TType + member HasCorrectObjArgs: m:range -> bool + member IsAccessible: m:range * ad:AccessorDomain -> bool + member IsCandidate: m:range * ad:AccessorDomain -> bool + member AllCalledArgs: CalledArg list list + member AllUnnamedCalledArgs: CalledArg list /// The argument analysis for each set of curried arguments @@ -155,8 +206,11 @@ type CalledMeth<'T> = /// Named setters member AssignedItemSetters: AssignedItemSetter<'T> list + member AssignedNamedArgs: AssignedCalledArg<'T> list list + member AssignedUnnamedArgs: AssignedCalledArg<'T> list list + member AssignsAllNamedArgs: bool /// The property related to the method we're attempting to call, if any @@ -182,21 +236,34 @@ type CalledMeth<'T> = /// The formal instantiation of the method we're attempting to call member CallerTyArgs: TType list + member HasCorrectArity: bool + member HasCorrectGenericArity: bool + member HasOptArgs: bool + member HasOutArgs: bool /// The method we're attempting to call member Method: MethInfo + member NumArgSets: int + member NumAssignedProps: int + member NumCalledTyArgs: int + member NumCallerTyArgs: int + member ParamArrayCalledArgOpt: CalledArg option + member ParamArrayCallerArgs: CallerArg<'T> list option + member TotalNumAssignedNamedArgs: int + member TotalNumUnnamedCalledArgs: int + member TotalNumUnnamedCallerArgs: int /// Unassigned args @@ -207,8 +274,11 @@ type CalledMeth<'T> = /// Unnamed called out args: return these as part of the return tuple member UnnamedCalledOutArgs: CalledArg list + member UsesParamArrayConversion: bool + member amap: ImportMap + member infoReader: InfoReader val NamesOfCalledArgs: calledArgs:CalledArg list -> Ident list @@ -219,7 +289,7 @@ type ArgumentAnalysis = | CallerLambdaHasArgTypes of TType list | CalledArgMatchesType of TType -val ExamineMethodForLambdaPropagation: x:CalledMeth -> (ArgumentAnalysis list list * (Ident * ArgumentAnalysis) list list) option +val ExamineMethodForLambdaPropagation: x:CalledMeth -> ad:AccessorDomain -> (ArgumentAnalysis list list * (Ident * ArgumentAnalysis) list list) option /// Is this a 'base' call val IsBaseCall: objArgs:Expr list -> bool @@ -260,12 +330,37 @@ val BuildNewDelegateExpr: eventInfoOpt:EventInfo option * g:TcGlobals * amap:Imp val CoerceFromFSharpFuncToDelegate: g:TcGlobals -> amap:ImportMap -> infoReader:InfoReader -> ad:AccessorDomain -> callerArgTy:TType -> m:range -> callerArgExpr:Expr -> delegateTy:TType -> Expr -val AdjustCallerArgExprForCoercions: g:TcGlobals -> amap:ImportMap -> infoReader:InfoReader -> ad:AccessorDomain -> isOutArg:bool -> calledArgTy:TType -> reflArgInfo:ReflectedArgInfo -> callerArgTy:TType -> m:range -> callerArgExpr:Expr -> 'a option * Expr +val AdjustExprForTypeDirectedConversions: + tcVal:(ValRef -> ValUseFlag -> TType list -> range -> Expr * TType) -> + g: TcGlobals -> + amap:ImportMap -> + infoReader:InfoReader -> + ad:AccessorDomain -> + reqdTy:TType -> + actualTy:TType -> + m:range -> + expr:Expr + -> Expr + +val AdjustCallerArgExpr: + tcVal:(ValRef -> ValUseFlag -> TType list -> range -> Expr * TType) -> + g:TcGlobals -> + amap:ImportMap -> + infoReader:InfoReader -> + ad:AccessorDomain -> + isOutArg:bool -> + calledArgTy:TType -> + reflArgInfo:ReflectedArgInfo -> + callerArgTy:TType -> + m:range -> + callerArgExpr:Expr -> + 'a option * Expr /// Build the argument list for a method call. Adjust for param array, optional arguments, byref arguments and coercions. /// For example, if you pass an F# reference cell to a byref then we must get the address of the /// contents of the ref. Likewise lots of adjustments are made for optional arguments etc. val AdjustCallerArgs: + tcVal:(ValRef -> ValUseFlag -> TType list -> range -> Expr * TType) -> tcFieldInit:(range -> AbstractIL.IL.ILFieldInit -> Const) -> eCallerMemberName:string option -> infoReader:InfoReader -> diff --git a/src/fsharp/NicePrint.fs b/src/fsharp/NicePrint.fs index fb4127adb3a..4ffa52da0aa 100755 --- a/src/fsharp/NicePrint.fs +++ b/src/fsharp/NicePrint.fs @@ -2213,7 +2213,15 @@ let prettyLayoutOfMethInfoFreeStyle infoReader m denv typarInst minfo = InfoMemb let prettyLayoutOfPropInfoFreeStyle g amap m denv d = InfoMemberPrinting.prettyLayoutOfPropInfoFreeStyle g amap m denv d /// Convert a MethInfo to a string -let stringOfMethInfo infoReader m denv d = bufs (fun buf -> InfoMemberPrinting.formatMethInfoToBufferFreeStyle infoReader m denv buf d) +let stringOfMethInfo infoReader m denv minfo = + bufs (fun buf -> InfoMemberPrinting.formatMethInfoToBufferFreeStyle infoReader m denv buf minfo) + +/// Convert MethInfos to lines separated by newline including a newline as the first character +let multiLineStringOfMethInfos infoReader m denv minfos = + minfos + |> List.map (stringOfMethInfo infoReader m denv) + |> List.map (sprintf "%s %s" System.Environment.NewLine) + |> String.concat "" /// Convert a ParamData to a string let stringOfParamData denv paramData = bufs (fun buf -> InfoMemberPrinting.formatParamDataToBuffer denv buf paramData) diff --git a/src/fsharp/NicePrint.fsi b/src/fsharp/NicePrint.fsi index 54dbc524c03..303770e5a2f 100644 --- a/src/fsharp/NicePrint.fsi +++ b/src/fsharp/NicePrint.fsi @@ -57,7 +57,9 @@ val prettyLayoutOfMethInfoFreeStyle: infoReader:InfoReader -> m:range -> denv:Di val prettyLayoutOfPropInfoFreeStyle: g:TcGlobals -> amap:ImportMap -> m:range -> denv:DisplayEnv -> d:PropInfo -> Layout -val stringOfMethInfo: infoReader:InfoReader -> m:range -> denv:DisplayEnv -> d:MethInfo -> string +val stringOfMethInfo: infoReader:InfoReader -> m:range -> denv:DisplayEnv -> minfo:MethInfo -> string + +val multiLineStringOfMethInfos: infoReader:InfoReader -> m:range -> denv:DisplayEnv -> minfos:MethInfo list -> string val stringOfParamData: denv:DisplayEnv -> paramData:ParamData -> string diff --git a/src/fsharp/SyntaxTreeOps.fs b/src/fsharp/SyntaxTreeOps.fs index ec0f6b90f83..ee67ac7738a 100644 --- a/src/fsharp/SyntaxTreeOps.fs +++ b/src/fsharp/SyntaxTreeOps.fs @@ -565,7 +565,8 @@ let mkSynBindingRhs staticOptimizations rhsExpr mRhs retInfo = let rhsExpr = List.foldBack (fun (c, e1) e2 -> SynExpr.LibraryOnlyStaticOptimization (c, e1, e2, mRhs)) staticOptimizations rhsExpr let rhsExpr, retTyOpt = match retInfo with - | Some (SynReturnInfo((ty, SynArgInfo(rAttribs, _, _)), tym)) -> SynExpr.Typed (rhsExpr, ty, rhsExpr.Range), Some(SynBindingReturnInfo(ty, tym, rAttribs) ) + | Some (SynReturnInfo((ty, SynArgInfo(rAttribs, _, _)), tym)) -> + SynExpr.Typed (rhsExpr, ty, rhsExpr.Range), Some(SynBindingReturnInfo(ty, tym, rAttribs) ) | None -> rhsExpr, None rhsExpr, retTyOpt diff --git a/src/fsharp/TypedTreeOps.fs b/src/fsharp/TypedTreeOps.fs index 76e55725904..679f59a1693 100644 --- a/src/fsharp/TypedTreeOps.fs +++ b/src/fsharp/TypedTreeOps.fs @@ -3280,6 +3280,11 @@ let mkNullableTy (g: TcGlobals) ty = TType_app (g.system_Nullable_tcref, [ty]) let mkListTy (g: TcGlobals) ty = TType_app (g.list_tcr_nice, [ty]) +let isValueOptionTy (g: TcGlobals) ty = + match tryTcrefOfAppTy g ty with + | ValueNone -> false + | ValueSome tcref -> tyconRefEq g g.valueoption_tcr_canon tcref + let isOptionTy (g: TcGlobals) ty = match tryTcrefOfAppTy g ty with | ValueNone -> false diff --git a/src/fsharp/TypedTreeOps.fsi b/src/fsharp/TypedTreeOps.fsi index 402208b2be5..4830cf4ee19 100755 --- a/src/fsharp/TypedTreeOps.fsi +++ b/src/fsharp/TypedTreeOps.fsi @@ -1427,6 +1427,9 @@ val mkVoidPtrTy: TcGlobals -> TType /// Build a single-dimensional array type val mkArrayType: TcGlobals -> TType -> TType +/// Determine if a type is a value option type +val isValueOptionTy: TcGlobals -> TType -> bool + /// Determine if a type is an option type val isOptionTy: TcGlobals -> TType -> bool diff --git a/src/fsharp/fscmain.fs b/src/fsharp/fscmain.fs index 5bce29fd229..947839cd5f6 100644 --- a/src/fsharp/fscmain.fs +++ b/src/fsharp/fscmain.fs @@ -18,7 +18,7 @@ open FSharp.Compiler.Text [] do () - + [] let main(argv) = diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index 571179889ff..f72e0f364d2 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -87,6 +87,11 @@ Atribut sestavení {0} odkazuje na navržené sestavení {1}, které se nedá načíst nebo neexistuje. Ohlášená výjimka: {2} – {3} + + additional type-directed conversions + additional type-directed conversions + + applicative computation expressions aplikativní výpočetní výrazy @@ -452,6 +457,11 @@ Sadu .NET SDK pro tento skript nešlo určit. Pokud se skript nachází v adresáři používajícím global.json, zkontrolujte, jestli je nainstalovaná odpovídající sada .NET SDK. Neočekávaná chyba {0}. + + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Tato funkce se v této verzi jazyka F# nepodporuje. Abyste mohli tuto funkci používat, možná bude nutné přidat /langversion:preview. @@ -487,6 +497,21 @@ Typy Byref nejsou v deklaraci otevřeného typu povolené. + + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. Atribut InlineIfLambda je možné použít pouze u parametrů vložených funkcí metod s typem funkce nebo typem delegáta F#. @@ -567,6 +592,11 @@ Použití obnovitelného kódu nebo obnovitelných stavových strojů vyžaduje /langversion:preview. + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + Invalid interpolated string. {0} Neplatný interpolovaný řetězec. {0} @@ -673,12 +703,12 @@ - All elements of a list must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of a list must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Všechny elementy výrazu konstruktoru seznamu musí mít stejný typ. Očekávalo se, že tento výraz bude mít typ {0}, ale tady je typu {1}. - All elements of an array must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of an array must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Všechny elementy výrazu konstruktoru pole musí mít stejný typ. Očekávalo se, že tento výraz bude mít typ {0}, ale tady je typu {1}. @@ -693,12 +723,12 @@ - All branches of an 'if' expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Všechny větve výrazu if musí mít stejný typ. Očekávalo se, že tento výraz bude mít typ {0}, ale tady je typu {1}. - All branches of a pattern match expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Všechny větve výrazu porovnání vzorů musí vracet hodnoty stejného typu. První větev vrátila hodnotu typu {0}, ale tato větev vrátila hodnotu typu {1}. diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index 110a87552df..6c0199593c1 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -87,6 +87,11 @@ Das Assemblyattribut "{0}" verweist auf eine Designerassembly "{1}", die entweder nicht geladen werden kann oder nicht vorhanden ist. Gemeldete Ausnahme: {2} – {3} + + additional type-directed conversions + additional type-directed conversions + + applicative computation expressions applikative Berechnungsausdrücke @@ -452,6 +457,11 @@ Das .NET SDK für dieses Skript konnte nicht ermittelt werden. Wenn sich das Skript in einem Verzeichnis mit "global.json" befindet, stellen Sie sicher, dass das entsprechende .NET SDK installiert ist. Unerwarteter Fehler: {0}. + + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Dieses Feature wird in dieser Version von F# nicht unterstützt. Möglicherweise müssen Sie "/langversion:preview" hinzufügen, um dieses Feature zu verwenden. @@ -487,6 +497,21 @@ Byref-Typen sind in einer Deklaration für offene Typen nicht zulässig. + + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. Das "InlineIfLambda-Attribut" darf nur für Parameter von Inlinefunktionen von Methoden verwendet werden, deren Typ ein Funktions-oder F #-Delegattyp ist. @@ -567,6 +592,11 @@ Die Verwendung von Fortsetzbarem Code oder fortsetzbaren Zustandscomputern erfordert /langversion:preview + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + Invalid interpolated string. {0} Ungültige interpolierte Zeichenfolge. {0} @@ -673,12 +703,12 @@ - All elements of a list must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of a list must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Alle Elemente eines Listenkonstruktorausdrucks müssen den gleichen Typ aufweisen. Es wurde erwartet, dass dieser Ausdruck den Typ "{0}" aufweist, hier liegt aber der Typ "{1}" vor. - All elements of an array must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of an array must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Alle Elemente eines Arraykonstruktorausdrucks müssen den gleichen Typ aufweisen. Es wurde erwartet, dass dieser Ausdruck den Typ "{0}" aufweist, hier liegt aber der Typ "{1}" vor. @@ -693,12 +723,12 @@ - All branches of an 'if' expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Alle Branches eines if-Ausdrucks müssen den gleichen Typ aufweisen. Es wurde erwartet, dass dieser Ausdruck den Typ "{0}" aufweist, hier liegt aber der Typ "{1}" vor. - All branches of a pattern match expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Alle Branches eines Musterübereinstimmungsausdrucks müssen Werte des gleichen Typs zurückgeben. Der erste Branch hat einen Wert vom Typ "{0}" zurückgegeben, aber dieser Branch gab einen Wert vom Typ "{1}" zurück. diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index 645efaa8a30..26afffe9372 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -87,6 +87,11 @@ El atributo de ensamblado "{0}" hace referencia a un ensamblado de diseñador "{1}" que no se puede cargar o no existe. Se notificó la excepción: {2} - {3}. + + additional type-directed conversions + additional type-directed conversions + + applicative computation expressions expresiones de cálculo aplicativas @@ -442,6 +447,11 @@ No se pudo determinar el SDK de .NET para este script. Si el script está en un directorio que usa una instancia de "global.json", asegúrese de que el SDK de .NET pertinente esté instalado. La salida de "{0} --version" en el directorio "{1}" era "{2}", con el código de salida "{3}". + + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + + The .NET SDK for this script could not be determined. dotnet.exe could not be found ensure a .NET SDK is installed. No se pudo determinar el SDK de .NET para este script. No se encontró dotnet.exe. Asegúrese de tener instalado un SDK de .NET. @@ -487,6 +497,21 @@ No se permiten tipos byref en una declaración de tipo abierto. + + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. El atributo "InlineIfLambda" solo se puede usar en los parámetros de funciones insertadas de métodos cuyo tipo es una función o un tipo de delegado F#. @@ -567,6 +592,11 @@ El uso de código reanudable o de máquinas de estado reanudables requiere /langversion:preview + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + Invalid interpolated string. {0} Cadena interpolada no válida. {0} @@ -673,12 +703,12 @@ - All elements of a list must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of a list must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Todas las ramas de una expresión de constructor de lista deben tener el mismo tipo. Se esperaba que esta expresión tuviera el tipo "{0}", pero aquí tiene el tipo "{1}". - All elements of an array must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of an array must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Todos los elementos de una expresión de constructor de matriz deben tener el mismo tipo. Se esperaba que esta expresión tuviera el tipo "{0}", pero aquí tiene el tipo "{1}". @@ -693,12 +723,12 @@ - All branches of an 'if' expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Todas las ramas de una expresión "if" deben devolver el mismo tipo. Se esperaba que esta expresión tuviera el tipo "{0}", pero aquí tiene el tipo "{1}". - All branches of a pattern match expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Todas las ramas de una expresión de coincidencia de patrón deben devolver valores del mismo tipo. La primera rama devolvió un valor de tipo "{0}", pero esta rama devolvió un valor de tipo "{1}". diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index ec0a3649ed2..12a7a9edee6 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -87,6 +87,11 @@ L'attribut d'assembly '{0}' fait référence à un assembly de concepteur '{1}' qui ne peut pas être chargé ou qui n'existe pas. Exception signalée : {2} - {3} + + additional type-directed conversions + additional type-directed conversions + + applicative computation expressions expressions de calcul applicatives @@ -442,6 +447,11 @@ Le kit SDK .NET de ce script n'a pas pu être déterminé. Si le script se trouve dans un répertoire utilisant un fichier 'global.json', vérifiez que le kit SDK .NET approprié est installé. La sortie de '{0} --version' dans le répertoire '{1}' était '{2}', et le code de sortie était '{3}'. + + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + + The .NET SDK for this script could not be determined. dotnet.exe could not be found ensure a .NET SDK is installed. Impossible de déterminer le Kit de développement logiciel (SDK) .NET pour ce script. dotnet.exe est introuvable pour garantir l’installation d’un kit SDK .NET. @@ -487,6 +497,21 @@ Les types Byref ne sont pas autorisés dans une déclaration de type ouverte. + + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. L’attribut « InlineIfLambda » ne peut être utilisé que sur les paramètres des fonctions incorporées des méthodes dont le type est une fonction ou un type délégué F#. @@ -567,6 +592,11 @@ L’utilisation de code pouvant être repris ou de machines d’état pouvant être reprises nécessite /langversion:preview + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + Invalid interpolated string. {0} Chaîne interpolée non valide. {0} @@ -673,12 +703,12 @@ - All elements of a list must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of a list must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Tous les éléments d'une expression comportant un constructeur de liste doivent avoir le même type. Cette expression était censée avoir le type '{0}', mais elle a ici le type '{1}'. - All elements of an array must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of an array must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Tous les éléments d'une expression comportant un constructeur de tableau doivent avoir le même type. Cette expression était censée avoir le type '{0}', mais elle a ici le type '{1}'. @@ -693,12 +723,12 @@ - All branches of an 'if' expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Toutes les branches d'une expression 'if' doivent avoir le même type. Cette expression était censée avoir le type '{0}', mais elle a ici le type '{1}'. - All branches of a pattern match expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Toutes les branches d'une expression comportant des critères spéciaux doivent retourner des valeurs du même type. La première branche a retourné une valeur de type '{0}', mais cette branche a retourné une valeur de type '{1}'. diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index 38e315f8ca8..dff4e4b91e9 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -87,6 +87,11 @@ L'attributo di assembly '{0}' fa riferimento a un assembly '{1}' della finestra di progettazione che non è stato caricato o non esiste. L'eccezione restituita è {2} - {3} + + additional type-directed conversions + additional type-directed conversions + + applicative computation expressions espressioni di calcolo applicativo @@ -442,6 +447,11 @@ Non è stato possibile determinare la versione di .NET SDK per questo script. Se lo script si trova in una directory che usa un file 'global.json', assicurarsi che sia installata la versione pertinente di .NET SDK. L'output di '{0} --version' nella directory '{1}' è '{2}' e il codice di uscita è '{3}'. + + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + + The .NET SDK for this script could not be determined. dotnet.exe could not be found ensure a .NET SDK is installed. Non e stato possibile determinare il Software Development Kit .NET per questo script. Non è stato possibile trovare dotnet.exe; assicurarsi che sia installato un Software Development Kit .NET. @@ -487,6 +497,21 @@ I tipi byref non sono consentiti in una dichiarazione di tipo aperto. + + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. L'attributo 'InlineIfLambda' può essere usato solo in parametri di funzioni impostate come inline di metodi il cui tipo è un tipo di funzione o delegato F#. @@ -567,6 +592,11 @@ Per l'uso del codice ripristinabile o delle macchine a stati ripristinabili è richiesto /langversion:preview + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + Invalid interpolated string. {0} La stringa interpolata non è valida. {0} @@ -673,12 +703,12 @@ - All elements of a list must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of a list must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Il tipo di tutti gli elementi di un'espressione di costruttore di elenco deve essere lo stesso. Il tipo previsto di questa espressione è '{0}', ma quello effettivo è '{1}'. - All elements of an array must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of an array must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Il tipo di tutti gli elementi di un'espressione di costruttore di matrice deve essere lo stesso. Il tipo previsto di questa espressione è '{0}', ma quello effettivo è '{1}'. @@ -693,12 +723,12 @@ - All branches of an 'if' expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Il tipo di tutti i rami di un'espressione 'if' deve essere lo stesso. Il tipo previsto di questa espressione è '{0}', ma quello effettivo è '{1}'. - All branches of a pattern match expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Tutti i rami di un'espressione di criteri di ricerca devono restituire valori dello stesso tipo. Il primo ramo ha restituito un valore di tipo '{0}', ma questo ramo ha restituito un valore di tipo '{1}'. diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index 3c1c09ac722..2d053be9854 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -87,6 +87,11 @@ アセンブリ属性 '{0}' は、デザイナー アセンブリ '{1}' を参照していますが、これは読み込むことができないか、存在していません。報告された例外: {2} - {3} + + additional type-directed conversions + additional type-directed conversions + + applicative computation expressions 適用できる計算式 @@ -442,6 +447,11 @@ このスクリプトの .NET SDK を特定できませんでした。このスクリプトが、'global.json' が使用されているディレクトリにある場合は、関連する .NET SDK がインストールされていることを確認してください。ディレクトリ '{1}' の '{0} --version' からの出力は '{2}' で、終了コードは '{3}' でした。 + + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + + The .NET SDK for this script could not be determined. dotnet.exe could not be found ensure a .NET SDK is installed. このスクリプトの .NET SDK を特定できませんでした。dotnet.exe が見つかりませんでした。 .NET SDK がインストールされていることをご確認ください。 @@ -487,6 +497,21 @@ Byref 型は、オープン型宣言では使用できません。 + + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. 'InlineIfLambda' 属性を使用できるのは、型が関数または F# デリゲート型であるメソッドのインライン関数のパラメーターに対してのみです。 @@ -567,6 +592,11 @@ 再開可能なコードまたは再開可能なステート マシンを使用するには、/langversion:preview が必要です + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + Invalid interpolated string. {0} 補間された文字列が無効です。{0} @@ -673,12 +703,12 @@ - All elements of a list must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of a list must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. リスト コンストラクター式のすべての要素は同じ型である必要があります。この式に必要な型は '{0}' ですが、ここでは型 '{1}' になっています。 - All elements of an array must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of an array must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. 配列コンストラクター式の要素はすべて同じ型である必要があります。この式に必要な型は '{0}' ですが、ここでは型 '{1}' になっています。 @@ -693,12 +723,12 @@ - All branches of an 'if' expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. if' 式のすべてのブランチは同じ型である必要があります。この式に必要な型は '{0}' ですが、ここでは型 '{1}' になっています。 - All branches of a pattern match expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. パターン マッチ式のすべてのブランチは、同じ型の値を返す必要があります。最初のブランチが返した値の型は '{0}' ですが、このブランチが返した値の型は '{1}' です。 diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index a8e8d4a8baf..7a7552c7cc2 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -87,6 +87,11 @@ '{0}' 어셈블리 특성이 로드할 수 없거나 존재하지 않는 디자이너 어셈블리'{1}'을(를) 참조합니다. 보고된 예외: {2} - {3} + + additional type-directed conversions + additional type-directed conversions + + applicative computation expressions 적용 가능한 계산 식 @@ -442,6 +447,11 @@ 이 스크립트에 대한 .NET SDK를 확인할 수 없습니다. 스크립트가 'global.json'을 사용하는 디렉터리에 있는 경우 관련 .NET SDK가 설치되어 있는지 확인하세요. '{1}' 디렉터리에 있는 '{0} --version'의 출력은 '{2}'이고 종료 코드는 '{3}'입니다. + + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + + The .NET SDK for this script could not be determined. dotnet.exe could not be found ensure a .NET SDK is installed. 이 스크립트의 .NET SDK를 확인할 수 없습니다. dotnet.exe를 찾을 수 없습니다. .NET SDK가 설치되어 있는지 확인하세요. @@ -487,6 +497,21 @@ Byref 형식은 개방형 형식 선언에서 허용되지 않습니다. + + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. 'InlineIfLambda' 특성은 형식이 함수 또는 F# 대리자 형식인 메서드의 인라인 함수 매개 변수에만 사용할 수 있습니다. @@ -567,6 +592,11 @@ 다시 시작 가능한 코드 또는 다시 시작 가능한 상태 시스템을 사용하려면 /langversion:preview가 필요합니다. + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + Invalid interpolated string. {0} 잘못된 보간 문자열. {0} @@ -673,12 +703,12 @@ - All elements of a list must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of a list must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. 목록 생성자의 모든 요소는 동일한 형식이어야 합니다. 이 식에는 '{0}' 형식이 필요하지만 여기에서는 '{1}' 형식이 지정되었습니다. - All elements of an array must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of an array must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. 배열 생성자의 모든 요소는 동일한 형식이어야 합니다. 이 식에는 '{0}' 형식이 필요하지만 여기에서는 '{1}' 형식이 지정되었습니다. @@ -693,12 +723,12 @@ - All branches of an 'if' expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. if' 식의 모든 분기는 동일한 형식이어야 합니다. 이 식에는 '{0}' 형식이 필요하지만 여기에서는 '{1}' 형식이 지정되었습니다. - All branches of a pattern match expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. 패턴 일치 식의 모든 분기는 동일한 형식의 값을 반환해야 합니다. 첫 번째 분기는 '{0}' 형식의 값을 반환했지만 이 분기는 '{1}' 형식의 값을 반환했습니다. diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index f1a0d33896d..258e1793045 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -87,6 +87,11 @@ Atrybut zestawu „{0}” odwołuje się do zestawu projektanta „{1}”, którego nie można załadować lub który nie istnieje. Zgłoszony wyjątek: {2} — {3} + + additional type-directed conversions + additional type-directed conversions + + applicative computation expressions praktyczne wyrażenia obliczeniowe @@ -442,6 +447,11 @@ Nie można określić zestawu .NET SDK dla tego skryptu. Jeśli skrypt znajduje się w katalogu korzystającym z pliku „global.json”, upewnij się, że zainstalowano odpowiedni zestaw .NET SDK. Dane wyjściowe polecenia „{0} --version” w katalogu „{1}” to „{2}”, a kod zakończenia to „{3}”. + + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + + The .NET SDK for this script could not be determined. dotnet.exe could not be found ensure a .NET SDK is installed. Nie można określić zestawu .NET SDK dla tego skryptu. Nie można odnaleźć pliku dotnet.exe. Upewnij się, że zestaw .NET SDK jest zainstalowany. @@ -487,6 +497,21 @@ Typy ByRef są niedozwolone w deklaracji typu otwartego. + + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. Atrybut "InlineIfLambda" może być używany tylko w przypadku parametrów funkcji z podkreśleniem metod, których typ to funkcja lub typ delegata języka F #. @@ -567,6 +592,11 @@ Używanie kodu z możliwością wznowienia lub automatów stanów z możliwością wznowienia wymaga parametru /langversion: wersja zapoznawcza + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + Invalid interpolated string. {0} Nieprawidłowy ciąg interpolowany. {0} @@ -673,12 +703,12 @@ - All elements of a list must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of a list must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Wszystkie elementy wyrażenia konstruktora listy muszą mieć ten sam typ. Oczekiwano, że to wyrażenie będzie miało typ „{0}”, ale tutaj ma typ „{1}”. - All elements of an array must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of an array must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Wszystkie elementy wyrażenia konstruktora tablicy muszą mieć ten sam typ. Oczekiwano, że to wyrażenie będzie miało typ „{0}”, ale tutaj ma typ „{1}”. @@ -693,12 +723,12 @@ - All branches of an 'if' expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Wszystkie gałęzie wyrażenia „if” muszą mieć ten sam typ. Oczekiwano, że to wyrażenie będzie miało typ „{0}”, ale tutaj ma typ „{1}”. - All branches of a pattern match expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Wszystkie gałęzie wyrażenia dopasowania do wzorca muszą zwracać wartości tego samego typu. Pierwsza gałąź zwróciła wartość typu „{0}”, ale ta gałąź zwróciła wartość typu „{1}” diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index 63b84c9560e..5d2af8b5ec2 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -87,6 +87,11 @@ O atributo de assembly '{0}' refere-se a um assembly de designer '{1}' que não pode ser carregado ou que não existe. A exceção relatada foi {2} – {3} + + additional type-directed conversions + additional type-directed conversions + + applicative computation expressions expressões de computação aplicáveis @@ -442,6 +447,11 @@ Não foi possível determinar o SDK do .NET para esse script. Se o script estiver em um diretório usando um 'global.json', verifique se o SDK relevante do .NET está instalado. A saída de '{0} --version' no diretório '{1}' foi: '{2}' e o código de saída foi '{3}'. + + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + + The .NET SDK for this script could not be determined. dotnet.exe could not be found ensure a .NET SDK is installed. Não foi possível determinar o .NET SDK para este script. Não foi possível encontrar dotnet.exe e certifique-se de que o SDK do .NET esteja instalado. @@ -487,6 +497,21 @@ Os tipos Byref não são permitidos em uma declaração de tipo aberto. + + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. O atributo 'InlineIfLambda' só pode ser usado em parâmetros de funções de métodos em linha cujo tipo seja uma função ou F# tipo delegado. @@ -567,6 +592,11 @@ Usar código retomável ou máquinas de estado retomável requer /langversion:preview + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + Invalid interpolated string. {0} Cadeia de caracteres interpolada inválida. {0} @@ -673,12 +703,12 @@ - All elements of a list must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of a list must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Todos os elementos de uma expressão do construtor de lista devem ter o mesmo tipo. Essa expressão deveria ter o tipo '{0}', mas aqui tem o tipo '{1}'. - All elements of an array must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of an array must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Todos os elementos de uma expressão do construtor de matriz devem ter o mesmo tipo. Essa expressão deveria ter o tipo '{0}', mas aqui tem o tipo '{1}'. @@ -693,12 +723,12 @@ - All branches of an 'if' expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Todas as ramificações de uma expressão 'if' devem ter o mesmo tipo. Essa expressão deveria ter o tipo '{0}', mas aqui tem o tipo '{1}'. - All branches of a pattern match expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Todos os branches de uma expressão correspondente ao padrão precisam retornar valores do mesmo tipo. O primeiro branch retornou um valor do tipo '{0}', mas este branch retornou um valor do tipo '{1}'. diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index bce26055b51..3ca74c1c375 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -87,6 +87,11 @@ Атрибут сборки "{0}" ссылается на сборку конструктора "{1}", которая не может быть загружена или не существует. Получено исключение: {2} — {3} + + additional type-directed conversions + additional type-directed conversions + + applicative computation expressions применимые вычислительные выражения @@ -442,6 +447,11 @@ Не удалось определить пакет SDK .NET для этого сценария. Если сценарий находится в каталоге с использованием "global.json", убедитесь, что установлен соответствующий пакет SDK .NET. Выходные данные команды "{0} --version" в каталоге "{1}" — "{2}", а код выхода — "{3}". + + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + + The .NET SDK for this script could not be determined. dotnet.exe could not be found ensure a .NET SDK is installed. Не удалось определить пакет SDK .NET для этого сценария. Не удалось найти dotnet.exe. Убедитесь, что пакет SDK .NET установлен. @@ -487,6 +497,21 @@ Типы ByRef запрещены в объявлении открытого типа. + + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. Атрибут "InlineIfLambda" может использоваться только в параметрах встраиваемых функций методов, типом которых является функция или делегат F#. @@ -567,6 +592,11 @@ Для использования возобновляемого кода или возобновляемых конечных автоматов требуется /langversion:preview + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + Invalid interpolated string. {0} Недопустимая интерполированная строка. {0} @@ -673,12 +703,12 @@ - All elements of a list must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of a list must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Все элементы выражения конструктора списка должны иметь один и тот же тип. В этом выражении ожидалось использование типа "{0}", но используется тип "{1}". - All elements of an array must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of an array must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Все элементы выражения конструктора массива должны иметь один и тот же тип. В этом выражении ожидалось использование типа "{0}", но используется тип "{1}". @@ -693,12 +723,12 @@ - All branches of an 'if' expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Все ветви выражения "if" должны иметь один и тот же тип. В этом выражении ожидалось использование типа "{0}", но используется тип "{1}". - All branches of a pattern match expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Все ветви выражения сопоставления шаблонов должны возвращать значения одного типа. Первая ветвь возвратила значение типа "{0}", а эта ветвь — типа "{1}". diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index 599f0b5415f..1dede9ff194 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -87,6 +87,11 @@ '{0}' bütünleştirilmiş kod özniteliği, yüklenemeyen veya mevcut olmayan '{1}' tasarımcı bütünleştirilmiş koduna başvuruyor. Bildirilen özel durum: {2} - {3} + + additional type-directed conversions + additional type-directed conversions + + applicative computation expressions uygulama hesaplama ifadeleri @@ -442,6 +447,11 @@ Bu betik için .NET SDK belirlenemedi. Betik 'global.json' kullanan bir dizindeyse, ilgili .NET SDK'nın yüklü olduğundan emin olun. '{1}' dizinindeki '{0} --version' çıkışı: '{2}' ve çıkış kodu: '{3}'. + + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + + The .NET SDK for this script could not be determined. dotnet.exe could not be found ensure a .NET SDK is installed. Bu betik için .NET SDK belirlenemedi. dotnet.exe bulunamadı, bir .NET SDK'nın yüklü olduğundan emin olun. @@ -487,6 +497,21 @@ Açık tür bildiriminde Byref türlerine izin verilmez. + + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. 'InlineIfLambda' özniteliği yalnızca işlev veya F# temsilci türündeki yöntemlerin satır içine alınmış işlev parametrelerinde kullanılabilir. @@ -567,6 +592,11 @@ Sürdürülebilir kod veya sürdürülebilir durum makinelerini kullanmak için /langversion:preview gerekir + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + Invalid interpolated string. {0} Geçersiz düz metin arasına kod eklenmiş dize. {0} @@ -673,12 +703,12 @@ - All elements of a list must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of a list must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Bir list constructor ifadesinin tüm öğeleri aynı türe sahip olmalıdır. Bu ifadenin '{0}' türünde olması bekleniyordu ancak burada '{1}' türünde. - All elements of an array must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of an array must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. Bir array constructor ifadesinin tüm öğeleri aynı türe sahip olmalıdır. Bu ifadenin '{0}' türünde olması bekleniyordu ancak burada '{1}' türünde. @@ -693,12 +723,12 @@ - All branches of an 'if' expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Bir 'if' ifadesinin tüm dalları aynı türe sahip olmalıdır. Bu ifadenin '{0}' türünde olması bekleniyordu ancak burada '{1}' türünde. - All branches of a pattern match expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. Bir desen eşleştirme ifadesinin tüm dalları aynı türdeki değerleri döndürmelidir. Birinci dal '{0}' türünde bir değer döndürdü ancak bu dal '{1}' türünde bir değer döndürdü. diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index ff843a2abeb..1ae6a4fab73 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -87,6 +87,11 @@ 程序集属性“{0}”引用了无法加载或不存在的设计器程序集“{1}”。报告的异常是: {2} - {3} + + additional type-directed conversions + additional type-directed conversions + + applicative computation expressions 适用的计算表达式 @@ -442,6 +447,11 @@ 无法确定此脚本的 .NET SDK。如果脚本在使用 "global.json" 的目录中,请确保已安装相关的 .NET SDK。目录“{1}”中 "{0} --version" 的输出为“{2}”,退出代码为“{3}”。 + + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + + The .NET SDK for this script could not be determined. dotnet.exe could not be found ensure a .NET SDK is installed. 无法确定此脚本的 .NET SDK。找不到 dotnet.exe,请确保安装了 .NET SDK。 @@ -487,6 +497,21 @@ 在开放类型声明中不允许使用 Byref 类型。 + + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. "InlineIfLambda" 特性只能用于类型为函数或 F# 委托类型的方法的内联函数的参数。 @@ -567,6 +592,11 @@ 使用可恢复代码或可恢复状态机需要 /langversion:preview + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + Invalid interpolated string. {0} 内插字符串无效。{0} @@ -673,12 +703,12 @@ - All elements of a list must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of a list must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. 列表构造函数表达式的所有元素必须具有同一类型。此表达式的类型应为“{0}”,但此处类型为“{1}”。 - All elements of an array must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of an array must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. 数组构造函数表达式的所有元素必须具有同一类型。此表达式的类型应为“{0}”,但此处类型为“{1}”。 @@ -693,12 +723,12 @@ - All branches of an 'if' expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. if 表达式的所有分支必须具有同一类型。此表达式的类型应为“{0}”,但此处类型为“{1}”。 - All branches of a pattern match expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. 模式匹配表达式的所有分支必须返回相同类型的值。第一个分支返回“{0}”类型的值,但此分支返回“{1}”类型的值。 diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index 4aaa9187995..5cd1f25b532 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -87,6 +87,11 @@ 無法載入組件屬性 '{0}' 參考的設計工具組件 '{1}' 或其不存在。回報的例外狀況: {2} - {3} + + additional type-directed conversions + additional type-directed conversions + + applicative computation expressions 適用的計算運算式 @@ -442,6 +447,11 @@ 無法判斷這個指令碼的 .NET SDK。如果指令碼位於使用 'global.json' 的目錄中,請確認已安裝相關的 .NET SDK。目錄 '{1}' 中 '{0} --version' 的輸出為: '{2}',結束代碼為 '{3}'。 + + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + This expression has type '{0}' and is only made compatible with type '{1}' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are:{2} + + The .NET SDK for this script could not be determined. dotnet.exe could not be found ensure a .NET SDK is installed. 無法判斷此指令碼的 .NET SDK。找不到 dotnet.exe,請確保已安裝 .NET SDK。 @@ -487,6 +497,21 @@ 開放式類型宣告中不允許 Byref 類型。 + + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression uses a built-in implicit conversion to convert type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. + + + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3391\". + + The 'InlineIfLambda' attribute may only be used on parameters of inlined functions of methods whose type is a function or F# delegate type. 'InlineIfLambda' 屬性只能用於類型為函式或 F# 委派類型之方法的內嵌函式參數。 @@ -567,6 +592,11 @@ 使用可繼續的程式碼或可繼續的狀態機器需要 /langversion:preview + + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + This expression implicitly converts type '{0}' to type '{1}'. See https://aka.ms/fsharp-implicit-convs. + + Invalid interpolated string. {0} 插補字串無效。{0} @@ -673,12 +703,12 @@ - All elements of a list must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of a list must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. 清單建構函式運算式的所有分支都必須是同一種類型。此運算式應具備類型 '{0}',但卻為類型 '{1}'。 - All elements of an array must be of the same type as the first element, which here is '{0}'. This element has type '{1}'. + All elements of an array must be implicitly convertible to the type of the first element, which here is '{0}'. This element has type '{1}'. 陣列建構函式運算式的所有項目都必須是同一種類型。此運算式應具備類型 '{0}',但卻是類型 '{1}'。 @@ -693,12 +723,12 @@ - All branches of an 'if' expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. if' 運算式的所有分支都必須是同一種類型。此運算式應具備類型 '{0}',但卻是類型 '{1}'。 - All branches of a pattern match expression must return values of the same type as the first branch, which here is '{0}'. This branch returns a value of type '{1}'. + All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is '{0}'. This branch returns a value of type '{1}'. 模式比對運算式的所有分支,都必須傳回相同類型的值。第一個分支傳回了類型 '{0}' 的值,但此分支卻傳回了類型 '{1}' 的值。 diff --git a/tests/FSharp.Compiler.ComponentTests/Diagnostics/async.fs b/tests/FSharp.Compiler.ComponentTests/Diagnostics/async.fs index 2c52972d2c2..d868564e980 100644 --- a/tests/FSharp.Compiler.ComponentTests/Diagnostics/async.fs +++ b/tests/FSharp.Compiler.ComponentTests/Diagnostics/async.fs @@ -35,7 +35,7 @@ module async = |> ignore // This test was automatically generated (moved from FSharpQA suite - Diagnostics/async) - //All branches of an 'if' expression must return values of the same type as the first branch + //All branches of an 'if' expression must return values implicitly convertible to the type of the first branch [] let ``async - ReturnBangNonAsync_IfThenElse.fs - --warnaserror+ --test:ErrorRanges --flaterrors`` compilation = compilation @@ -44,7 +44,7 @@ module async = |> compile |> shouldFail |> withErrorCode 0001 - |> withDiagnosticMessageMatches "All branches of an 'if' expression must return values of the same type as the first branch" + |> withDiagnosticMessageMatches "All branches of an 'if' expression must return values implicitly convertible to the type of the first branch" |> ignore // This test was automatically generated (moved from FSharpQA suite - Diagnostics/async) diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ElseBranchHasWrongTypeTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ElseBranchHasWrongTypeTests.fs index 439ada429ca..250fc8f674b 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ElseBranchHasWrongTypeTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ElseBranchHasWrongTypeTests.fs @@ -18,7 +18,7 @@ let y = |> typecheck |> shouldFail |> withSingleDiagnostic (Error 1, Line 5, Col 10, Line 5, Col 13, - "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'.") + "All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is 'string'. This branch returns a value of type 'int'.") [] let ``Else branch is a function that returns int while if branch is string``() = @@ -32,7 +32,7 @@ let y = |> typecheck |> shouldFail |> withSingleDiagnostic (Error 1, Line 6, Col 10, Line 6, Col 14, - "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'.") + "All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is 'string'. This branch returns a value of type 'int'.") [] @@ -50,7 +50,7 @@ let y = |> typecheck |> shouldFail |> withSingleDiagnostic (Error 1, Line 9, Col 10, Line 9, Col 13, - "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'.") + "All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is 'string'. This branch returns a value of type 'int'.") [] @@ -70,7 +70,7 @@ let y = |> typecheck |> shouldFail |> withSingleDiagnostic (Error 1, Line 11, Col 10, Line 11, Col 13, - "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'int'.") + "All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is 'string'. This branch returns a value of type 'int'.") [] @@ -151,7 +151,7 @@ let y : bool = |> shouldFail |> withDiagnostics [ (Error 1, Line 4, Col 19, Line 4, Col 22, "The 'if' expression needs to have type 'bool' to satisfy context type requirements. It currently has type 'string'.") - (Error 1, Line 5, Col 10, Line 5, Col 13, "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'bool'. This branch returns a value of type 'string'.")] + (Error 1, Line 5, Col 10, Line 5, Col 13, "All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is 'bool'. This branch returns a value of type 'string'.")] [] @@ -166,6 +166,6 @@ else |> typecheck |> shouldFail |> withDiagnostics [ - (Error 1, Line 5, Col 19, Line 5, Col 22, "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'bool'. This branch returns a value of type 'string'.") - (Error 1, Line 6, Col 10, Line 6, Col 13, "All branches of an 'if' expression must return values of the same type as the first branch, which here is 'bool'. This branch returns a value of type 'string'.") + (Error 1, Line 5, Col 19, Line 5, Col 22, "All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is 'bool'. This branch returns a value of type 'string'.") + (Error 1, Line 6, Col 10, Line 6, Col 13, "All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is 'bool'. This branch returns a value of type 'string'.") (Warning 20, Line 3, Col 1, Line 6, Col 13, "The result of this expression has type 'bool' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.")] diff --git a/tests/FSharp.Compiler.ComponentTests/resources/tests/Diagnostics/async/ReturnBangNonAsync_IfThenElse.fs b/tests/FSharp.Compiler.ComponentTests/resources/tests/Diagnostics/async/ReturnBangNonAsync_IfThenElse.fs index 74f2176d4cf..ecc1175241d 100644 --- a/tests/FSharp.Compiler.ComponentTests/resources/tests/Diagnostics/async/ReturnBangNonAsync_IfThenElse.fs +++ b/tests/FSharp.Compiler.ComponentTests/resources/tests/Diagnostics/async/ReturnBangNonAsync_IfThenElse.fs @@ -1,6 +1,6 @@ // #Regression #Diagnostics #Async // Regression tests for FSHARP1.0:4394 -//All branches of an 'if' expression must return values of the same type as the first branch +//All branches of an 'if' expression must return values implicitly convertible to the type of the first branch async { if true then return () else diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj index 3ad6dd6550f..f08d6de964e 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj @@ -72,7 +72,7 @@ ParserTests.fs - + Program.fs @@ -83,4 +83,4 @@ - \ No newline at end of file + diff --git a/tests/fsharp/TypeProviderTests.fs b/tests/fsharp/TypeProviderTests.fs index cfc83d5f7f4..76561ffdaaf 100644 --- a/tests/fsharp/TypeProviderTests.fs +++ b/tests/fsharp/TypeProviderTests.fs @@ -227,7 +227,7 @@ let ``negative type provider tests`` (name:string) = rm cfg "provider.dll" - fsc cfg "--out:provider.dll -a" ["provider.fsx"] + fsc cfg "--out:provider.dll -g --optimize- -a" ["provider.fsx"] fsc cfg "--out:provider_providerAttributeErrorConsume.dll -a" ["providerAttributeError.fsx"] @@ -235,11 +235,11 @@ let ``negative type provider tests`` (name:string) = rm cfg "helloWorldProvider.dll" - fsc cfg "--out:helloWorldProvider.dll -a" [".." ++ "helloWorld" ++ "provider.fsx"] + fsc cfg "--out:helloWorldProvider.dll -g --optimize- -a" [".." ++ "helloWorld" ++ "provider.fsx"] rm cfg "MostBasicProvider.dll" - fsc cfg "--out:MostBasicProvider.dll -a" ["MostBasicProvider.fsx"] + fsc cfg "--out:MostBasicProvider.dll -g --optimize- -a" ["MostBasicProvider.fsx"] let preprocess name pref = let dirp = (dir |> Commands.pathAddBackslash) diff --git a/tests/fsharp/core/access/test.fsx b/tests/fsharp/core/access/test.fsx index 26034dc99e5..3d7e7f1624a 100644 --- a/tests/fsharp/core/access/test.fsx +++ b/tests/fsharp/core/access/test.fsx @@ -267,7 +267,6 @@ module RestrictedRecordsAndUnionsUsingPrivateAndInternalTypes = (*--------------------*) - #if TESTS_AS_APP let RUN() = !failures #else diff --git a/tests/fsharp/core/auto-widen/5.0/test.bsl b/tests/fsharp/core/auto-widen/5.0/test.bsl new file mode 100644 index 00000000000..d7d611dd20d --- /dev/null +++ b/tests/fsharp/core/auto-widen/5.0/test.bsl @@ -0,0 +1,879 @@ + +test.fsx(11,20,11,21): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(14,20,14,41): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(17,20,17,44): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(20,21,20,24): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + ''a * 'b' + +test.fsx(28,31,28,32): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(33,27,33,28): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(33,29,33,30): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(36,56,36,57): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(36,58,36,59): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(39,43,39,44): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(39,45,39,46): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(44,41,44,42): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(45,48,45,49): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(45,50,45,51): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(48,30,48,31): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(48,32,48,33): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(58,22,58,24): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(59,22,59,23): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(60,28,60,29): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(60,30,60,31): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'int64'. This element has type 'int'. + +test.fsx(60,32,60,33): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'int64'. This element has type 'int'. + +test.fsx(60,34,60,35): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'int64'. This element has type 'int'. + +test.fsx(61,28,61,29): typecheck error FS0001: This expression was expected to have type + 'float' +but here has type + 'int' + +test.fsx(61,30,61,31): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'float'. This element has type 'int'. + +test.fsx(61,32,61,33): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'float'. This element has type 'int'. + +test.fsx(61,34,61,35): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'float'. This element has type 'int'. + +test.fsx(62,30,62,31): typecheck error FS0001: This expression was expected to have type + 'float32' +but here has type + 'int' + +test.fsx(62,32,62,33): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'float32'. This element has type 'int'. + +test.fsx(62,34,62,35): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'float32'. This element has type 'int'. + +test.fsx(62,36,62,37): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'float32'. This element has type 'int'. + +test.fsx(63,22,63,43): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(64,28,64,49): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(64,50,64,71): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'int64'. This element has type 'int'. + +test.fsx(67,20,67,23): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(67,20,67,23): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(68,22,68,25): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(68,22,68,25): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(69,26,69,29): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(69,26,69,29): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(93,13,93,20): typecheck error FS0041: No overloads match for method 'M1'. + +Known type of argument: int + +Available overloads: + - static member C.M1 : x:int64 -> unit // Argument 'x' doesn't match + - static member C.M1 : x:string -> 'a0 // Argument 'x' doesn't match + +test.fsx(99,13,99,22): typecheck error FS0041: No overloads match for method 'M1'. + +Known type of argument: x:int + +Available overloads: + - static member C.M1 : ?x:int64 -> unit // Argument 'x' doesn't match + - static member C.M1 : x:string -> 'a0 // Argument 'x' doesn't match + +test.fsx(116,20,116,21): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(121,14,121,21): typecheck error FS0041: No overloads match for method 'M1'. + +Known type of argument: int + +Available overloads: + - static member C.M1 : [] x:int64 [] -> int64 // Argument 'x' doesn't match + - static member C.M1 : [] x:int64 [] -> int64 // Argument at index 1 doesn't match + +test.fsx(122,19,122,20): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(122,22,122,23): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(127,14,127,21): typecheck error FS0041: No overloads match for method 'M1'. + +Known type of argument: int + +Available overloads: + - static member C.M1 : [] x:double [] -> double // Argument 'x' doesn't match + - static member C.M1 : [] x:double [] -> double // Argument at index 1 doesn't match + +test.fsx(128,19,128,20): typecheck error FS0001: This expression was expected to have type + 'double' +but here has type + 'int' + +test.fsx(128,22,128,23): typecheck error FS0001: This expression was expected to have type + 'double' +but here has type + 'int' + +test.fsx(135,18,135,19): typecheck error FS0001: This expression was expected to have type + 'C' +but here has type + 'int' + +test.fsx(140,18,140,19): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(145,18,145,19): typecheck error FS0001: This expression was expected to have type + 'decimal' +but here has type + 'int' + +test.fsx(147,18,147,19): typecheck error FS0001: This expression was expected to have type + 'decimal' +but here has type + 'int' + +test.fsx(149,39,149,41): typecheck error FS0001: This expression was expected to have type + 'Xml.Linq.XNamespace' +but here has type + 'string' + +test.fsx(154,18,154,20): typecheck error FS0001: This expression was expected to have type + 'Xml.Linq.XNamespace' +but here has type + 'string' + +test.fsx(159,18,159,21): typecheck error FS0001: This expression was expected to have type + 'Xml.Linq.XName' +but here has type + 'string' + +test.fsx(165,18,165,19): typecheck error FS0001: The type 'int' is not compatible with the type 'C' + +test.fsx(165,17,165,20): typecheck error FS0193: Type constraint mismatch. The type + 'int' +is not compatible with type + 'C' + + +test.fsx(172,18,172,21): typecheck error FS0001: The type 'Y' is not compatible with the type 'X' + +test.fsx(172,17,172,22): typecheck error FS0193: Type constraint mismatch. The type + 'Y' +is not compatible with type + 'X' + + +test.fsx(178,20,178,21): typecheck error FS0001: This expression was expected to have type + 'C' +but here has type + 'int' + +test.fsx(180,15,180,16): typecheck error FS0001: The type 'int' is not compatible with the type 'C' + +test.fsx(186,27,186,28): typecheck error FS0001: This expression was expected to have type + 'Nullable' +but here has type + 'int' + +test.fsx(188,15,188,16): typecheck error FS0001: This expression was expected to have type + 'Nullable' +but here has type + 'int' + +test.fsx(191,21,191,24): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + ''a * 'b' + +test.fsx(192,27,192,28): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(192,29,192,30): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(195,56,195,57): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(195,58,195,59): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(198,49,198,50): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(198,51,198,54): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'float' + +test.fsx(201,33,201,34): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(201,35,201,38): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'float' + +test.fsx(204,43,204,44): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(204,45,204,46): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(207,20,207,35): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'R' + +test.fsx(210,22,210,41): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'R' + +test.fsx(213,20,213,36): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'SR' + +test.fsx(216,22,216,43): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'SR' + +test.fsx(219,20,219,33): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'U' + +test.fsx(222,21,222,31): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'U' + +test.fsx(225,21,225,31): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int -> U' + +test.fsx(228,21,228,40): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'SU' + +test.fsx(231,21,231,37): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'SU' + +test.fsx(234,21,234,37): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int -> SU' + +test.fsx(237,13,237,14): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(237,16,237,19): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'byte' + +test.fsx(237,30,237,33): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'float' + +test.fsx(237,35,237,36): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(243,42,243,43): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(246,45,246,46): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(246,54,246,57): typecheck error FS0001: All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is 'obj'. This branch returns a value of type 'float'. + +test.fsx(246,65,246,68): typecheck error FS0001: All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is 'obj'. This branch returns a value of type 'byte'. + +test.fsx(248,49,248,50): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(248,51,248,52): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(253,36,253,37): typecheck error FS0001: This expression was expected to have type + 'IComparable' +but here has type + 'int' + +test.fsx(256,30,256,39): typecheck error FS0001: This expression was expected to have type + 'Array' +but here has type + 'uint16 []' + +test.fsx(258,30,258,38): typecheck error FS0001: This expression was expected to have type + 'Array' +but here has type + ''a []' + +test.fsx(260,36,260,38): typecheck error FS0001: This expression was expected to have type + 'IComparable' +but here has type + 'Numerics.BigInteger' + +test.fsx(263,44,263,63): typecheck error FS0001: This expression was expected to have type + 'IComparable' +but here has type + 'string' + +test.fsx(266,44,266,68): typecheck error FS0001: This expression was expected to have type + 'IComparable' +but here has type + 'string' + +test.fsx(268,21,268,45): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(270,36,270,60): typecheck error FS0001: This expression was expected to have type + 'IComparable' +but here has type + 'string' + +test.fsx(275,35,275,36): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(275,37,275,38): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(276,35,276,40): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(276,41,276,42): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(277,44,277,45): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(278,44,278,45): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(278,55,278,58): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'float' + +test.fsx(279,68,279,71): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'float' + +test.fsx(280,82,280,85): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'float' + +test.fsx(282,21,282,22): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(283,22,283,29): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(284,21,284,23): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(285,22,285,33): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(286,22,286,45): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'IComparable' + +test.fsx(287,22,287,24): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(288,22,288,24): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(289,21,289,76): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'ICloneable' + +test.fsx(290,21,290,23): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(291,21,291,30): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(291,21,291,30): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(292,24,292,26): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(295,34,295,35): typecheck error FS0001: The 'if' expression needs to have type 'obj' to satisfy context type requirements. It currently has type 'int'. + +test.fsx(295,41,295,44): typecheck error FS0001: All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is 'obj'. This branch returns a value of type 'float'. + +test.fsx(296,35,296,36): typecheck error FS0001: The 'if' expression needs to have type 'obj' to satisfy context type requirements. It currently has type 'int'. + +test.fsx(296,42,296,45): typecheck error FS0001: All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is 'obj'. This branch returns a value of type 'float'. + +test.fsx(297,35,297,36): typecheck error FS0001: The 'if' expression needs to have type 'obj' to satisfy context type requirements. It currently has type 'int'. + +test.fsx(297,52,297,55): typecheck error FS0001: All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is 'obj'. This branch returns a value of type 'byte'. + +test.fsx(297,61,297,64): typecheck error FS0001: All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is 'obj'. This branch returns a value of type 'float'. + +test.fsx(300,25,300,26): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(300,37,300,40): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'float' + +test.fsx(303,25,303,26): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(306,45,306,46): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(306,54,306,57): typecheck error FS0001: All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is 'obj'. This branch returns a value of type 'float'. + +test.fsx(309,19,309,20): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(310,32,310,33): typecheck error FS0001: The 'if' expression needs to have type 'obj' to satisfy context type requirements. It currently has type 'int'. + +test.fsx(310,39,310,42): typecheck error FS0001: All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is 'obj'. This branch returns a value of type 'float'. + +test.fsx(313,37,313,38): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(314,37,314,38): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(317,50,317,51): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(319,52,319,53): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(320,37,320,38): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(323,57,323,58): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(325,57,325,58): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(326,37,326,38): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(328,42,328,43): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(330,42,330,43): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(331,38,331,39): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(335,28,335,39): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a list' + +test.fsx(337,9,338,34): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a list' + +test.fsx(340,9,341,33): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a list' + +test.fsx(343,9,344,35): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a list' + +test.fsx(346,9,347,36): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a list' + +test.fsx(349,9,349,36): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a list' + +test.fsx(351,9,351,40): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a list' + +test.fsx(353,9,354,40): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a list' + +test.fsx(356,9,357,41): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a list' + +test.fsx(359,9,359,35): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a list' + +test.fsx(361,9,362,36): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a list' + +test.fsx(364,9,365,37): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a list' + +test.fsx(368,39,368,40): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(369,39,369,40): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(372,52,372,53): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(374,54,374,55): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(375,39,375,40): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(378,59,378,60): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(380,59,380,60): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(381,39,381,40): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(383,44,383,45): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(385,44,385,45): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(386,40,386,41): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(390,28,390,41): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a []' + +test.fsx(391,30,392,57): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a []' + +test.fsx(393,30,394,56): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a []' + +test.fsx(395,30,396,58): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a []' + +test.fsx(397,30,398,59): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a []' + +test.fsx(399,30,399,59): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a []' + +test.fsx(400,30,400,63): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a []' + +test.fsx(401,30,402,63): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a []' + +test.fsx(403,30,404,64): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a []' + +test.fsx(405,31,405,59): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a []' + +test.fsx(406,31,407,60): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a []' + +test.fsx(408,31,409,61): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + ''a []' + +test.fsx(429,10,437,16): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + 'OtherSeq<'a>' + +test.fsx(448,9,450,49): typecheck error FS0001: This expression was expected to have type + 'seq' +but here has type + 'OtherSeqImpl<'a>' + +test.fsx(452,32,452,33): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(454,46,454,47): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' diff --git a/tests/fsharp/core/auto-widen/5.0/test.fsx b/tests/fsharp/core/auto-widen/5.0/test.fsx new file mode 100644 index 00000000000..1905c5977d0 --- /dev/null +++ b/tests/fsharp/core/auto-widen/5.0/test.fsx @@ -0,0 +1,467 @@ + +#r "System.Xml.Linq.dll" +#r "System.Xml.XDocument.dll" + +let mutable failures : string list = [] + +open System + +module BasicTypeDirectedConversionsToObj = + // Constant expression + let x1 : obj = 1 + + // Field literal expressions + let x2 : obj = System.Int32.MaxValue + + // Field literal expressions + let x3 : obj = System.Int32.Parse("12") + + // Tuple expressions + let x4 : obj = (1,2) + + // Arithmetic expressions + // These do NOT permit type-directed subsumption nor widening because a generic return type is involved + // the is not yet committed + // let x : obj = 1 + 1 + + // Values + let x8 (s:string) : obj = s + +module BasicTypeDirectedConversionsToTuple = + + // Tuple expressions + let x2 : obj * obj = (1,2) + + // Let expressions + let x3 : (obj * obj) = (let x = 1 in let y = 2 in (x,y)) + + // Struct tuple expressions + let x4 : struct (obj * obj) = struct (1,2) + +module BasicTypeDirectedConversionsForFuncReturn = + + // Return in lambda expressions + let x5 : (unit -> obj) = (fun () -> 1) + let x6 : (unit -> obj * obj) = (fun () -> (1,2)) + + // Return in function expressions + let x7 () : obj * obj = (1,2) + +type R = { mutable F1: (obj * obj) } +[] +type SR = { mutable SF1: (obj * obj) } +type U = UnionCase0 | UnionCase1 of int +[] +type SU = StructUnionCase0 | StructUnionCase1 of int +module IntegerWidening = + let i1 = 0 + let x0 : int64 = i1 // integer value + let x1 : int64 = 0 // integer constant + let x2 : int64 list = [1;2;3;4] // within a list + let x3 : float list = [1;2;3;4] + let x4 : float32 list = [1;2;3;4] + let x5 : int64 = System.Int32.MaxValue + let x6 : int64 list = [System.Int32.MaxValue;System.Int32.MaxValue] + let f () = 1 + + let x7 : obj = f() + let x8 : int64 = f() + let x9 : int64 = id (f()) // generic does work + + // Arithmetic expressions + // These do NOT permit type-directed subsumption nor widening because a generic return type is involved + // the is not yet committed + // let x6 : int64 = 1 + 1 + // let x6 : int64 = id (1 + 1) + +module Overloads1 = + type C() = + static member M1(x:int) = 1 + static member M1(x:int64) = failwith "nope" + let x = C.M1(2) + +module Overloads2 = + type C() = + static member M1(x:int) = failwith "nope" + static member M1(x:int64) = printfn "ok at line %s" __LINE__ + let x = C.M1(2L) + +module Overloads3 = + type C() = + static member M1(x:string) = failwith "nope" + static member M1(x:int64) = printfn "ok at line %s" __LINE__ + let x = C.M1(2) + +module OverloadedOptionals1 = + type C() = + static member M1(x:string) = failwith "nope" + static member M1(?x:int64) = printfn "ok at line %s" __LINE__ + let x = C.M1(x=2) + +module OverloadedOptionals2 = + type C() = + static member M1(?x:int) = printfn "ok at line %s" __LINE__ + static member M1(?x:int64) = failwith "nope" + let x = C.M1(x=2) + +module OverloadedOptionals3 = + type C() = + static member M1(?x:int) = failwith "nope" + static member M1(?x:int64) = printfn "ok at line %s" __LINE__ + let x = C.M1(x=2L) + +module Optionals1 = + type C() = + static member M1(?x:int64) = 1 + let x = C.M1(x=2) + +module ParamArray1 = + type C() = + static member M1([] x:int64[]) = Array.sum x + let x1 = C.M1(2) + let x2 = C.M1(2, 3, 5L) + +module ParamArray2 = + type C() = + static member M1([] x:double[]) = Array.sum x + let x1 = C.M1(2) + let x2 = C.M1(2, 3, 5.0) + +module ConvertToSealedViaOpImplicit = + [] + type C() = + static member op_Implicit(x:int) = C() + static member M1(C:C) = 1 + let x = C.M1(2) + +module ConvertNoOverloadin = + type C() = + static member M1(x:int64) = 1 + let x = C.M1(2) + +module ConvertNoOverloadingViaOpImplicit = + type C() = + static member M1(x:decimal) = () + let x = C.M1(2) + +let d: decimal = 3 + +let ns : System.Xml.Linq.XNamespace = "" + +module ConvertViaOpImplicit2 = + type C() = + static member M1(ns:System.Xml.Linq.XNamespace) = 1 + let x = C.M1("") + +module ConvertViaOpImplicit3 = + type C() = + static member M1(ns:System.Xml.Linq.XName) = 1 + let x = C.M1("a") + +module ConvertViaOpImplicit4 = + type C() = + static member op_Implicit(x:int) = C() + static member M1(C:C) = 1 + let x = C.M1(2) + +module ConvertViaOpImplicit5 = + type X() = + static member M1(x:X) = 1 + type Y() = + static member op_Implicit(y:Y) = X() + let x = X.M1(Y()) + +module ConvertViaOpImplicitGeneric = + type C<'T>() = + static member op_Implicit(x: 'T) = C<'T>() + + let c:C = 1 + let f (c:C) = 1 + let x = f 2 + +module ConvertViaNullable = + type C<'T>() = + static member op_Implicit(x: 'T) = C<'T>() + + let c:Nullable = 1 + let f (c:Nullable) = 1 + let x = f 2 + +let annotations = + let v1 : obj = (1,2) + let v2 : obj * obj = (1,2) + + // structure through let + let v3 : (obj * obj) = (let x = 1 in let y = 2 in (x,y)) + + // structure through let rec + let v4 : (obj * obj) = (let rec f x = x in (3,4.0)) + + // structure through sequence + let v5 : (obj * obj) = (); (3,4.0) + + // struct tuple + let v6 : struct (obj * obj) = struct (1,2) + + // record (both field and overall result) + let v7 : obj = { F1 = (1, 2) } + + // record + let v7a : obj = ({ F1 = (1, 2) } : R) + + // struct record (both field and overall result) + let v8 : obj = { SF1 = (1, 2) } + + // struct record (both field and overall result) + let v8a : obj = ({ SF1 = (1, 2) } : SR) + + // union + let v9 : obj = UnionCase1(3) + + // union + let v10 : obj = UnionCase0 + + // union as first-class + let v11 : obj = UnionCase1 + + // struct union + let v12 : obj = StructUnionCase1(3) + + // struct union + let v13 : obj = StructUnionCase0 + + // struct union as first-class + let v14 : obj = StructUnionCase1 + + // record (both field and overall result) + { F1 = (1, 2uy) }.F1 <- (3.0, 4) + + // anon record + let v15 : {| A: obj |} = {| A = 1 |} + + // lambda return + let v16 : (unit -> obj) = (fun () -> 1) + + // function lambda return + let v17 : (int -> obj) = (function 1 -> 1 | 2 -> 3.0 | _ -> 4uy) + + let v18 : (unit -> obj * obj) = (fun () -> (1,2)) + + // constants + (1 :> System.IComparable) |> ignore + + let v19 : System.IComparable = 1 + + // array constants + let v20 : System.Array = [| 1us |] + + let v21 : System.Array = [| 1I |] + + let v22 : System.IComparable = 1I + + // property + let v23 : System.IComparable = System.String.Empty + + // method + let v24 : System.IComparable = System.String.Format("") + + let v25 : obj = System.String.Format("") + + let v26 : System.IComparable = System.String.Format("") + + // array constants + + let v27 : obj[] = [| 1 |] + let v28 : (obj * obj)[] = [| (1,1) |] + let v29 : (obj * obj)[] = [| ("abc",1) |] + let v30 : (string * obj)[] = [| ("abc",1) |] + let v31 : (string * obj)[] = [| ("abc",1); ("abc",3.0) |] + let v32 : (string * obj)[] = [| Unchecked.defaultof<_>; ("abc",3.0) |] + let v33 : struct (string * obj)[] = [| Unchecked.defaultof<_>; struct ("abc",3.0) |] + + let v34 : obj = 1 + let v35 : obj = (1 : int) + let v36 : obj = "" + let v37 : obj = ("" : string) + let v38 : obj = ("" : System.IComparable) + let v39 : obj = ("" : _) + let v40 : obj = ("" : obj) + let v41 : obj = { new System.ICloneable with member x.Clone() = obj() } + let v42 : obj = "" + let v43 : obj = string "" + let v44 : obj = id "" + + // conditional + let v45 : obj = if true then 1 else 3.0 + let v46 : obj = (if true then 1 else 3.0) + let v47 : obj = (if true then 1 elif true then 2uy else 3.0) + + // try-with + let v48 : obj = try 1 with _ -> 3.0 + + // try-finally + let v49 : obj = try 1 finally () + + // match + let v50 : obj = match true with true -> 1 | _ -> 3.0 + () + +let f1 () : obj = 1 +let f2 () : obj = if true then 1 else 3.0 + +module TestComputedListExpressionsAtList = + let x1 : list = [ yield 1 ] + let x2 : list = [ yield 1; + if true then yield 2L ] + let x3 : list = [ yield 1L; + if true then yield 2 ] + let x4 : list = [ yield 1L; + while false do yield 2 ] + let x5 : list = [ yield 1; + while false do yield 2L ] + let x6 : list = [ while false do yield 2L ] + let x7 : list = [ for i in 0 .. 10 do yield 2 ] + let x8 : list = [ yield 1L + for i in 0 .. 10 do yield 2 ] + let x9 : list = [ yield 1 + for i in 0 .. 10 do yield 2L ] + let x10 : list = [ try yield 2 finally () ] + let x11 : list = [ yield 1L + try yield 2 finally () ] + let x12 : list = [ yield 1 + try yield 2L finally () ] + +module TestComputedListExpressionsAtSeq = + let x1 : seq = [ yield 1 ] + let x2 : seq = + [ yield 1; + if true then yield 2L ] + let x3 : seq = + [ yield 1L; + if true then yield 2 ] + let x4 : seq = + [ yield 1L; + while false do yield 2 ] + let x5 : seq = + [ yield 1; + while false do yield 2L ] + let x6 : seq = + [ while false do yield 2L ] + let x7 : seq = + [ for i in 0 .. 10 do yield 2 ] + let x8 : seq = + [ yield 1L + for i in 0 .. 10 do yield 2 ] + let x9 : seq = + [ yield 1 + for i in 0 .. 10 do yield 2L ] + let x10 : seq = + [ try yield 2 finally () ] + let x11 : seq = + [ yield 1L + try yield 2 finally () ] + let x12 : seq = + [ yield 1 + try yield 2L finally () ] + +module TestComputedArrayExpressionsAtArray = + let x1 : array = [| yield 1 |] + let x2 : array = [| yield 1; + if true then yield 2L |] + let x3 : array = [| yield 1L; + if true then yield 2 |] + let x4 : array = [| yield 1L; + while false do yield 2 |] + let x5 : array = [| yield 1; + while false do yield 2L |] + let x6 : array = [| while false do yield 2L |] + let x7 : array = [| for i in 0 .. 10 do yield 2 |] + let x8 : array = [| yield 1L + for i in 0 .. 10 do yield 2 |] + let x9 : array = [| yield 1 + for i in 0 .. 10 do yield 2L |] + let x10 : array = [| try yield 2 finally () |] + let x11 : array = [| yield 1L + try yield 2 finally () |] + let x12 : array = [| yield 1 + try yield 2L finally () |] + +module TestComputedArrayExpressionsAtSeq = + let x1 : seq = [| yield 1 |] + let x2 : seq = [| yield 1; + if true then yield 2L |] + let x3 : seq = [| yield 1L; + if true then yield 2 |] + let x4 : seq = [| yield 1L; + while false do yield 2 |] + let x5 : seq = [| yield 1; + while false do yield 2L |] + let x6 : seq = [| while false do yield 2L |] + let x7 : seq = [| for i in 0 .. 10 do yield 2 |] + let x8 : seq = [| yield 1L + for i in 0 .. 10 do yield 2 |] + let x9 : seq = [| yield 1 + for i in 0 .. 10 do yield 2L |] + let x10 : seq = [| try yield 2 finally () |] + let x11 : seq = [| yield 1L + try yield 2 finally () |] + let x12 : seq = [| yield 1 + try yield 2L finally () |] + +module TestInferObjExprTypeParamFromKNownType = + // Check we are inferring type int64 + let x1 : seq = + { new seq<_> with + member x.GetEnumerator() = + // The 'ToString("4")' would not resolve if the type parameter is not inferred by this point + x.GetEnumerator().Current.ToString("4") |> ignore + failwith "" + + interface System.Collections.IEnumerable with + member x.GetEnumerator() = failwith "" + } + + type OtherSeq<'T> = + inherit seq<'T> + + // Check we are inferring type int64 + let x2 : seq = + { new OtherSeq<_> with + member x.GetEnumerator() = + // The 'ToString("4")' would not resolve if the type parameter is not inferred by this point + x.GetEnumerator().Current.ToString("4") |> ignore + failwith "" + + interface System.Collections.IEnumerable with + member x.GetEnumerator() = failwith "" + } + + type OtherSeqImpl<'T>(f : 'T -> unit) = + interface OtherSeq<'T> with + member x.GetEnumerator() = + failwith "" + + interface System.Collections.IEnumerable with + member x.GetEnumerator() = failwith "" + + let x3 : seq = + new OtherSeqImpl<_>(fun x -> + // The 'ToString("4")' would not resolve if the type parameter is not inferred to be int64 by this point + x.ToString("4") |> ignore) + + let x4 : int64 * int32 = (3, 3) + + let x5 : {| A: int64; B: int32 |} = {| A=3; B=3 |} + +printfn "test done" + +let aa = + match failures with + | [] -> + stdout.WriteLine "Test Passed" + System.IO.File.WriteAllText("test.ok","ok") + exit 0 + | _ -> + printfn "Test Failed, failures = %A" failures + exit 1 + diff --git a/tests/fsharp/core/auto-widen/preview-default-warns/test.bsl b/tests/fsharp/core/auto-widen/preview-default-warns/test.bsl new file mode 100644 index 00000000000..b2b6a3e9b83 --- /dev/null +++ b/tests/fsharp/core/auto-widen/preview-default-warns/test.bsl @@ -0,0 +1,69 @@ + +test.fsx(147,18,147,19): typecheck error FS3391: This expression uses the implicit conversion 'Decimal.op_Implicit(value: int) : decimal' to convert type 'int' to type 'decimal'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(149,39,149,41): typecheck error FS3391: This expression uses the implicit conversion 'Xml.Linq.XNamespace.op_Implicit(namespaceName: string) : Xml.Linq.XNamespace' to convert type 'string' to type 'Xml.Linq.XNamespace'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(172,18,172,21): typecheck error FS3391: This expression uses the implicit conversion 'static member Y.op_Implicit : y:Y -> X' to convert type 'Y' to type 'X'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(172,18,172,21): typecheck error FS3391: This expression uses the implicit conversion 'static member Y.op_Implicit : y:Y -> X' to convert type 'Y' to type 'X'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(178,20,178,21): typecheck error FS3391: This expression uses the implicit conversion 'static member C.op_Implicit : x:'T -> C<'T>' to convert type 'int' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(180,15,180,16): typecheck error FS3391: This expression uses the implicit conversion 'static member C.op_Implicit : x:'T -> C<'T>' to convert type 'int' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(186,27,186,28): typecheck error FS3391: This expression uses the implicit conversion 'Nullable.op_Implicit(value: int) : Nullable' to convert type 'int' to type 'Nullable'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(188,15,188,16): typecheck error FS3391: This expression uses the implicit conversion 'Nullable.op_Implicit(value: int) : Nullable' to convert type 'int' to type 'Nullable'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(463,18,463,19): typecheck error FS0001: This expression was expected to have type + 'C' +but here has type + 'int' + +test.fsx(471,18,471,19): typecheck error FS0044: This construct is deprecated. nope + +test.fsx(482,18,482,21): typecheck error FS3387: This expression has type 'B' and is only made compatible with type 'C' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are: + static member B.op_Implicit : x:B -> C + static member C.op_Implicit : x:B -> C + +test.fsx(482,18,482,21): typecheck error FS3391: This expression uses the implicit conversion 'static member B.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(482,18,482,21): typecheck error FS3387: This expression has type 'B' and is only made compatible with type 'C' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are: + static member B.op_Implicit : x:B -> C + static member C.op_Implicit : x:B -> C + +test.fsx(482,18,482,21): typecheck error FS3391: This expression uses the implicit conversion 'static member B.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(507,18,507,21): typecheck error FS3391: This expression uses the implicit conversion 'static member C.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(507,18,507,21): typecheck error FS3391: This expression uses the implicit conversion 'static member C.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(519,18,519,21): typecheck error FS3391: This expression uses the implicit conversion 'static member B.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(519,18,519,21): typecheck error FS3391: This expression uses the implicit conversion 'static member B.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(538,18,538,21): typecheck error FS3391: This expression uses the implicit conversion 'static member C.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(538,18,538,21): typecheck error FS3391: This expression uses the implicit conversion 'static member C.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(546,30,546,31): typecheck error FS0001: This expression was expected to have type + 'float32' +but here has type + 'int' + +test.fsx(546,32,546,33): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'float32'. This element has type 'int'. + +test.fsx(546,34,546,35): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'float32'. This element has type 'int'. + +test.fsx(546,36,546,37): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'float32'. This element has type 'int'. + +test.fsx(547,28,547,32): typecheck error FS0001: This expression was expected to have type + 'float' +but here has type + 'float32' + +test.fsx(547,33,547,37): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'float'. This element has type 'float32'. + +test.fsx(547,38,547,42): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'float'. This element has type 'float32'. + +test.fsx(547,43,547,47): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'float'. This element has type 'float32'. diff --git a/tests/fsharp/core/auto-widen/preview-default-warns/test.fsx b/tests/fsharp/core/auto-widen/preview-default-warns/test.fsx new file mode 100644 index 00000000000..753a70f94ad --- /dev/null +++ b/tests/fsharp/core/auto-widen/preview-default-warns/test.fsx @@ -0,0 +1,574 @@ + +#r "System.Xml.Linq.dll" +#r "System.Xml.XDocument.dll" + +let mutable failures : string list = [] + +open System + +module BasicTypeDirectedConversionsToObj = + // Constant expression + let x1 : obj = 1 + + // Field literal expressions + let x2 : obj = System.Int32.MaxValue + + // Field literal expressions + let x3 : obj = System.Int32.Parse("12") + + // Tuple expressions + let x4 : obj = (1,2) + + // Arithmetic expressions + // These do NOT permit type-directed subsumption nor widening because a generic return type is involved + // the is not yet committed + // let x : obj = 1 + 1 + + // Values + let x8 (s:string) : obj = s + +module BasicTypeDirectedConversionsToTuple = + + // Tuple expressions + let x2 : obj * obj = (1,2) + + // Let expressions + let x3 : (obj * obj) = (let x = 1 in let y = 2 in (x,y)) + + // Struct tuple expressions + let x4 : struct (obj * obj) = struct (1,2) + +module BasicTypeDirectedConversionsForFuncReturn = + + // Return in lambda expressions + let x5 : (unit -> obj) = (fun () -> 1) + let x6 : (unit -> obj * obj) = (fun () -> (1,2)) + + // Return in function expressions + let x7 () : obj * obj = (1,2) + +type R = { mutable F1: (obj * obj) } +[] +type SR = { mutable SF1: (obj * obj) } +type U = UnionCase0 | UnionCase1 of int +[] +type SU = StructUnionCase0 | StructUnionCase1 of int +module IntegerWidening = + let i1 = 0 + let x0 : int64 = i1 // integer value + let x1 : int64 = 0 // integer constant + let x2 : int64 list = [1;2;3;4] // within a list + let x3 : float list = [1;2;3;4.0] + //let x4 : float32 list = [1;2;3;4] + let x5 : int64 = System.Int32.MaxValue + let x6 : int64 list = [System.Int32.MaxValue;System.Int32.MaxValue] + let f () = 1 + + let x7 : obj = f() + let x8 : int64 = f() + let x9 : int64 = id (f()) // generic does work + + // Arithmetic expressions + // These do NOT permit type-directed subsumption nor widening because a generic return type is involved + // the is not yet committed + // let x6 : int64 = 1 + 1 + // let x6 : int64 = id (1 + 1) + +module Overloads1 = + type C() = + static member M1(x:int) = 1 + static member M1(x:int64) = failwith "nope" + let x = C.M1(2) + +module Overloads2 = + type C() = + static member M1(x:int) = failwith "nope" + static member M1(x:int64) = printfn "ok at line %s" __LINE__ + let x = C.M1(2L) + +module Overloads3 = + type C() = + static member M1(x:string) = failwith "nope" + static member M1(x:int64) = printfn "ok at line %s" __LINE__ + let x = C.M1(2) + +module OverloadedOptionals1 = + type C() = + static member M1(x:string) = failwith "nope" + static member M1(?x:int64) = printfn "ok at line %s" __LINE__ + let x = C.M1(x=2) + +module OverloadedOptionals2 = + type C() = + static member M1(?x:int) = printfn "ok at line %s" __LINE__ + static member M1(?x:int64) = failwith "nope" + let x = C.M1(x=2) + +module OverloadedOptionals3 = + type C() = + static member M1(?x:int) = failwith "nope" + static member M1(?x:int64) = printfn "ok at line %s" __LINE__ + let x = C.M1(x=2L) + +module Optionals1 = + type C() = + static member M1(?x:int64) = 1 + let x = C.M1(x=2) + +module ParamArray1 = + type C() = + static member M1([] x:int64[]) = Array.sum x + let x1 = C.M1(2) + let x2 = C.M1(2, 3, 5L) + +module ParamArray2 = + type C() = + static member M1([] x:double[]) = Array.sum x + let x1 = C.M1(2) + let x2 = C.M1(2, 3, 5.0) + +module ConvertToSealedViaOpImplicit = + [] + type C() = + static member op_Implicit(x:int) = C() + static member M1(C:C) = 1 + let x = C.M1(2) + +module ConvertNoOverloadin = + type C() = + static member M1(x:int64) = 1 + let x = C.M1(2) + +module ConvertNoOverloadingViaOpImplicit = + type C() = + static member M1(x:decimal) = () + let x = C.M1(2) + +let d: decimal = 3 + +let ns : System.Xml.Linq.XNamespace = "" + +module ConvertViaOpImplicit2 = + type C() = + static member M1(ns:System.Xml.Linq.XNamespace) = 1 + let x = C.M1("") + +module ConvertViaOpImplicit3 = + type C() = + static member M1(ns:System.Xml.Linq.XName) = 1 + let x = C.M1("a") + +module ConvertViaOpImplicit4 = + type C() = + static member op_Implicit(x:int) = C() + static member M1(C:C) = 1 + let x = C.M1(2) + +module ConvertViaOpImplicit5 = + type X() = + static member M1(x:X) = 1 + type Y() = + static member op_Implicit(y:Y) = X() + let x = X.M1(Y()) + +module ConvertViaOpImplicitGeneric = + type C<'T>() = + static member op_Implicit(x: 'T) = C<'T>() + + let c:C = 1 + let f (c:C) = 1 + let x = f 2 + +module ConvertViaNullable = + type C<'T>() = + static member op_Implicit(x: 'T) = C<'T>() + + let c:Nullable = 1 + let f (c:Nullable) = 1 + let x = f 2 + +let annotations = + let v1 : obj = (1,2) + let v2 : obj * obj = (1,2) + + // structure through let + let v3 : (obj * obj) = (let x = 1 in let y = 2 in (x,y)) + + // structure through let rec + let v4 : (obj * obj) = (let rec f x = x in (3,4.0)) + + // structure through sequence + let v5 : (obj * obj) = (); (3,4.0) + + // struct tuple + let v6 : struct (obj * obj) = struct (1,2) + + // record (both field and overall result) + let v7 : obj = { F1 = (1, 2) } + + // record + let v7a : obj = ({ F1 = (1, 2) } : R) + + // struct record (both field and overall result) + let v8 : obj = { SF1 = (1, 2) } + + // struct record (both field and overall result) + let v8a : obj = ({ SF1 = (1, 2) } : SR) + + // union + let v9 : obj = UnionCase1(3) + + // union + let v10 : obj = UnionCase0 + + // union as first-class + let v11 : obj = UnionCase1 + + // struct union + let v12 : obj = StructUnionCase1(3) + + // struct union + let v13 : obj = StructUnionCase0 + + // struct union as first-class + let v14 : obj = StructUnionCase1 + + // record (both field and overall result) + { F1 = (1, 2uy) }.F1 <- (3.0, 4) + + // anon record + let v15 : {| A: obj |} = {| A = 1 |} + + // lambda return + let v16 : (unit -> obj) = (fun () -> 1) + + // function lambda return + let v17 : (int -> obj) = (function 1 -> 1 | 2 -> 3.0 | _ -> 4uy) + + let v18 : (unit -> obj * obj) = (fun () -> (1,2)) + + // constants + (1 :> System.IComparable) |> ignore + + let v19 : System.IComparable = 1 + + // array constants + let v20 : System.Array = [| 1us |] + + let v21 : System.Array = [| 1I |] + + let v22 : System.IComparable = 1I + + // property + let v23 : System.IComparable = System.String.Empty + + // method + let v24 : System.IComparable = System.String.Format("") + + let v25 : obj = System.String.Format("") + + let v26 : System.IComparable = System.String.Format("") + + // array constants + + let v27 : obj[] = [| 1 |] + let v28 : (obj * obj)[] = [| (1,1) |] + let v29 : (obj * obj)[] = [| ("abc",1) |] + let v30 : (string * obj)[] = [| ("abc",1) |] + let v31 : (string * obj)[] = [| ("abc",1); ("abc",3.0) |] + let v32 : (string * obj)[] = [| Unchecked.defaultof<_>; ("abc",3.0) |] + let v33 : struct (string * obj)[] = [| Unchecked.defaultof<_>; struct ("abc",3.0) |] + + let v34 : obj = 1 + let v35 : obj = (1 : int) + let v36 : obj = "" + let v37 : obj = ("" : string) + let v38 : obj = ("" : System.IComparable) + let v39 : obj = ("" : _) + let v40 : obj = ("" : obj) + let v41 : obj = { new System.ICloneable with member x.Clone() = obj() } + let v42 : obj = "" + let v43 : obj = string "" + let v44 : obj = id "" + + // conditional + let v45 : obj = if true then 1 else 3.0 + let v46 : obj = (if true then 1 else 3.0) + let v47 : obj = (if true then 1 elif true then 2uy else 3.0) + + // try-with + let v48 : obj = try 1 with _ -> 3.0 + + // try-finally + let v49 : obj = try 1 finally () + + // match + let v50 : obj = match true with true -> 1 | _ -> 3.0 + () + +let f1 () : obj = 1 +let f2 () : obj = if true then 1 else 3.0 + +module TestComputedListExpressionsAtList = + let x1 : list = [ yield 1 ] + let x2 : list = [ yield 1; + if true then yield 2L ] + let x3 : list = [ yield 1L; + if true then yield 2 ] + let x4 : list = [ yield 1L; + while false do yield 2 ] + let x5 : list = [ yield 1; + while false do yield 2L ] + let x6 : list = [ while false do yield 2L ] + let x7 : list = [ for i in 0 .. 10 do yield 2 ] + let x8 : list = [ yield 1L + for i in 0 .. 10 do yield 2 ] + let x9 : list = [ yield 1 + for i in 0 .. 10 do yield 2L ] + let x10 : list = [ try yield 2 finally () ] + let x11 : list = [ yield 1L + try yield 2 finally () ] + let x12 : list = [ yield 1 + try yield 2L finally () ] + +module TestComputedListExpressionsAtSeq = + let x1 : seq = [ yield 1 ] + let x2 : seq = + [ yield 1; + if true then yield 2L ] + let x3 : seq = + [ yield 1L; + if true then yield 2 ] + let x4 : seq = + [ yield 1L; + while false do yield 2 ] + let x5 : seq = + [ yield 1; + while false do yield 2L ] + let x6 : seq = + [ while false do yield 2L ] + let x7 : seq = + [ for i in 0 .. 10 do yield 2 ] + let x8 : seq = + [ yield 1L + for i in 0 .. 10 do yield 2 ] + let x9 : seq = + [ yield 1 + for i in 0 .. 10 do yield 2L ] + let x10 : seq = + [ try yield 2 finally () ] + let x11 : seq = + [ yield 1L + try yield 2 finally () ] + let x12 : seq = + [ yield 1 + try yield 2L finally () ] + +module TestComputedArrayExpressionsAtArray = + let x1 : array = [| yield 1 |] + let x2 : array = [| yield 1; + if true then yield 2L |] + let x3 : array = [| yield 1L; + if true then yield 2 |] + let x4 : array = [| yield 1L; + while false do yield 2 |] + let x5 : array = [| yield 1; + while false do yield 2L |] + let x6 : array = [| while false do yield 2L |] + let x7 : array = [| for i in 0 .. 10 do yield 2 |] + let x8 : array = [| yield 1L + for i in 0 .. 10 do yield 2 |] + let x9 : array = [| yield 1 + for i in 0 .. 10 do yield 2L |] + let x10 : array = [| try yield 2 finally () |] + let x11 : array = [| yield 1L + try yield 2 finally () |] + let x12 : array = [| yield 1 + try yield 2L finally () |] + +module TestComputedArrayExpressionsAtSeq = + let x1 : seq = [| yield 1 |] + let x2 : seq = [| yield 1; + if true then yield 2L |] + let x3 : seq = [| yield 1L; + if true then yield 2 |] + let x4 : seq = [| yield 1L; + while false do yield 2 |] + let x5 : seq = [| yield 1; + while false do yield 2L |] + let x6 : seq = [| while false do yield 2L |] + let x7 : seq = [| for i in 0 .. 10 do yield 2 |] + let x8 : seq = [| yield 1L + for i in 0 .. 10 do yield 2 |] + let x9 : seq = [| yield 1 + for i in 0 .. 10 do yield 2L |] + let x10 : seq = [| try yield 2 finally () |] + let x11 : seq = [| yield 1L + try yield 2 finally () |] + let x12 : seq = [| yield 1 + try yield 2L finally () |] + +module TestInferObjExprTypeParamFromKNownType = + // Check we are inferring type int64 + let x1 : seq = + { new seq<_> with + member x.GetEnumerator() = + // The 'ToString("4")' would not resolve if the type parameter is not inferred by this point + x.GetEnumerator().Current.ToString("4") |> ignore + failwith "" + + interface System.Collections.IEnumerable with + member x.GetEnumerator() = failwith "" + } + + type OtherSeq<'T> = + inherit seq<'T> + + // Check we are inferring type int64 + let x2 : seq = + { new OtherSeq<_> with + member x.GetEnumerator() = + // The 'ToString("4")' would not resolve if the type parameter is not inferred by this point + x.GetEnumerator().Current.ToString("4") |> ignore + failwith "" + + interface System.Collections.IEnumerable with + member x.GetEnumerator() = failwith "" + } + + type OtherSeqImpl<'T>(f : 'T -> unit) = + interface OtherSeq<'T> with + member x.GetEnumerator() = + failwith "" + + interface System.Collections.IEnumerable with + member x.GetEnumerator() = failwith "" + + let x3 : seq = + new OtherSeqImpl<_>(fun x -> + // The 'ToString("4")' would not resolve if the type parameter is not inferred to be int64 by this point + x.ToString("4") |> ignore) + + let x4 : int64 * int32 = (3, 3) + + let x5 : {| A: int64; B: int32 |} = {| A=3; B=3 |} + +// These tests are activate for the case where warnings are on +#if NEGATIVE +module TestAcessibilityOfOpImplicit = + [] + type C() = + static member private op_Implicit(x:int) = C() + static member M1(C:C) = 1 + let x = C.M1(2) + +module TestObsoleteOfOpImplicit = + [] + type C() = + [] + static member op_Implicit(x:int) = C() + static member M1(C:C) = 1 + let x = C.M1(2) + +module TestAmbiguousOpImplicit = + [] + type B() = + static member op_Implicit(x:B) = C(2) + + and [] C(x:int) = + static member op_Implicit(x:B) = C(1) + static member M1(C:C) = 1 + member _.Value = x + let x = C.M1(B()) + +#endif + +let report_failure (s : string) = + stderr.Write" NO: " + stderr.WriteLine s + failures <- failures @ [s] + +let test (s : string) b = + stderr.Write(s) + if b then stderr.WriteLine " OK" + else report_failure (s) + +let check s b1 b2 = test s (b1 = b2) + +module TestAmbiguousOpImplicitOkOneIsPrivate = + [] + type B() = + static member private op_Implicit(x:B) = C(1) + + and [] C(x:int) = + static member op_Implicit(x:B) = C(2) + static member M1(c:C) = c.Value + member _.Value = x + let x = C.M1(B()) + check "vewenlwevl" x 2 + +module TestAmbiguousOpImplicitOkOtherIsPrivate = + [] + type B() = + static member op_Implicit(x:B) = C(1) + + and [] C(x:int) = + static member private op_Implicit(x:B) = C(2) + static member M1(c:C) = c.Value + member _.Value = x + let x = C.M1(B()) + check "vewenlwevl" x 1 + +#nowarn "1215" +module TestExtrinsicOpImplicitIgnoredCompletely = + [] + type B() = class end + + and [] C(x:int) = + static member op_Implicit(x:B) = C(3) + static member M1(c:C) = c.Value + member _.Value = x + + [] + module Extensions = + type B with + // This gets ignored - a warning 1215 is actually reported implying this (ignored above) + static member op_Implicit(x:B) = C(1) + + let x = C.M1(B()) + check "vewenlwevlce" x 3 + +#nowarn "33" + + +#if NEGATIVE +module TestNoWidening = + let x4 : float32 list = [1;2;3;4] + let x5 : float list = [1.0f;2.0f;3.0f;4.0f] +#endif + + +module CheckNoWarningOnUsingImplicitForAPI = + type C() = + static member op_Implicit(x: int) = C() + static member op_Implicit(x: float) = C() + + + type API() = + static member M(c: C) = () + + API.M(3) + API.M(3.1) + +printfn "test done" + +let aa = + match failures with + | [] -> + stdout.WriteLine "Test Passed" + System.IO.File.WriteAllText("test.ok","ok") + exit 0 + | _ -> + printfn "Test Failed, failures = %A" failures + exit 1 + diff --git a/tests/fsharp/core/auto-widen/preview/test.bsl b/tests/fsharp/core/auto-widen/preview/test.bsl new file mode 100644 index 00000000000..9208628103e --- /dev/null +++ b/tests/fsharp/core/auto-widen/preview/test.bsl @@ -0,0 +1,640 @@ + +test.fsx(11,20,11,21): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(14,20,14,41): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(20,21,20,24): typecheck error FS3388: This expression implicitly converts type 'int * int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(28,31,28,32): typecheck error FS3388: This expression implicitly converts type 'string' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(33,27,33,28): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(33,29,33,30): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(36,56,36,57): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(36,58,36,59): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(39,43,39,44): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(39,45,39,46): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(44,41,44,42): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(45,48,45,49): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(45,50,45,51): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(48,30,48,31): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(48,32,48,33): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(58,22,58,24): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(58,22,58,24): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(59,22,59,23): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(59,22,59,23): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(60,28,60,29): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(60,28,60,29): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(60,30,60,31): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(60,30,60,31): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(60,32,60,33): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(60,32,60,33): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(60,34,60,35): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(60,34,60,35): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(61,28,61,29): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'float'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(61,28,61,29): typecheck error FS3388: This expression implicitly converts type 'int' to type 'float'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(61,30,61,31): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'float'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(61,30,61,31): typecheck error FS3388: This expression implicitly converts type 'int' to type 'float'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(61,32,61,33): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'float'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(61,32,61,33): typecheck error FS3388: This expression implicitly converts type 'int' to type 'float'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(63,22,63,43): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(63,22,63,43): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(64,28,64,49): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(64,28,64,49): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(64,50,64,71): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(64,50,64,71): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(67,20,67,23): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(67,20,67,23): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(68,22,68,25): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(68,22,68,25): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(68,22,68,25): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(68,22,68,25): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(69,26,69,29): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(69,26,69,29): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(69,26,69,29): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(69,26,69,29): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(93,18,93,19): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(93,18,93,19): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(99,20,99,21): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(99,20,99,21): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(116,20,116,21): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(116,20,116,21): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(121,19,121,20): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(121,19,121,20): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(122,19,122,20): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(122,19,122,20): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(122,22,122,23): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(122,22,122,23): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(127,19,127,20): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'double'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(127,19,127,20): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'double'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(128,19,128,20): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'double'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(128,19,128,20): typecheck error FS3388: This expression implicitly converts type 'int' to type 'double'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(128,22,128,23): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'double'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(128,22,128,23): typecheck error FS3388: This expression implicitly converts type 'int' to type 'double'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(135,18,135,19): typecheck error FS3390: This expression uses the implicit conversion 'static member C.op_Implicit : x:int -> C' to convert type 'int' to type 'C'. + +test.fsx(135,18,135,19): typecheck error FS3388: This expression implicitly converts type 'int' to type 'C'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(140,18,140,19): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(140,18,140,19): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(145,18,145,19): typecheck error FS3390: This expression uses the implicit conversion 'Decimal.op_Implicit(value: int) : decimal' to convert type 'int' to type 'decimal'. + +test.fsx(145,18,145,19): typecheck error FS3388: This expression implicitly converts type 'int' to type 'decimal'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(147,18,147,19): typecheck error FS3391: This expression uses the implicit conversion 'Decimal.op_Implicit(value: int) : decimal' to convert type 'int' to type 'decimal'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(147,18,147,19): typecheck error FS3388: This expression implicitly converts type 'int' to type 'decimal'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(149,39,149,41): typecheck error FS3391: This expression uses the implicit conversion 'Xml.Linq.XNamespace.op_Implicit(namespaceName: string) : Xml.Linq.XNamespace' to convert type 'string' to type 'Xml.Linq.XNamespace'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(149,39,149,41): typecheck error FS3388: This expression implicitly converts type 'string' to type 'Xml.Linq.XNamespace'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(154,18,154,20): typecheck error FS3390: This expression uses the implicit conversion 'Xml.Linq.XNamespace.op_Implicit(namespaceName: string) : Xml.Linq.XNamespace' to convert type 'string' to type 'Xml.Linq.XNamespace'. + +test.fsx(154,18,154,20): typecheck error FS3388: This expression implicitly converts type 'string' to type 'Xml.Linq.XNamespace'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(159,18,159,21): typecheck error FS3390: This expression uses the implicit conversion 'Xml.Linq.XName.op_Implicit(expandedName: string) : Xml.Linq.XName' to convert type 'string' to type 'Xml.Linq.XName'. + +test.fsx(159,18,159,21): typecheck error FS3388: This expression implicitly converts type 'string' to type 'Xml.Linq.XName'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(165,18,165,19): typecheck error FS3390: This expression uses the implicit conversion 'static member C.op_Implicit : x:int -> C' to convert type 'int' to type 'C'. + +test.fsx(165,18,165,19): typecheck error FS3388: This expression implicitly converts type 'int' to type 'C'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(172,18,172,21): typecheck error FS3391: This expression uses the implicit conversion 'static member Y.op_Implicit : y:Y -> X' to convert type 'Y' to type 'X'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(172,18,172,21): typecheck error FS3391: This expression uses the implicit conversion 'static member Y.op_Implicit : y:Y -> X' to convert type 'Y' to type 'X'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(178,20,178,21): typecheck error FS3391: This expression uses the implicit conversion 'static member C.op_Implicit : x:'T -> C<'T>' to convert type 'int' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(178,20,178,21): typecheck error FS3388: This expression implicitly converts type 'int' to type 'C'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(180,15,180,16): typecheck error FS3391: This expression uses the implicit conversion 'static member C.op_Implicit : x:'T -> C<'T>' to convert type 'int' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(180,15,180,16): typecheck error FS3388: This expression implicitly converts type 'int' to type 'C'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(186,27,186,28): typecheck error FS3391: This expression uses the implicit conversion 'Nullable.op_Implicit(value: int) : Nullable' to convert type 'int' to type 'Nullable'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(186,27,186,28): typecheck error FS3388: This expression implicitly converts type 'int' to type 'Nullable'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(188,15,188,16): typecheck error FS3391: This expression uses the implicit conversion 'Nullable.op_Implicit(value: int) : Nullable' to convert type 'int' to type 'Nullable'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(188,15,188,16): typecheck error FS3388: This expression implicitly converts type 'int' to type 'Nullable'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(191,21,191,24): typecheck error FS3388: This expression implicitly converts type 'int * int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(192,27,192,28): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(192,29,192,30): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(195,56,195,57): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(195,58,195,59): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(198,49,198,50): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(198,51,198,54): typecheck error FS3388: This expression implicitly converts type 'float' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(201,33,201,34): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(201,35,201,38): typecheck error FS3388: This expression implicitly converts type 'float' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(204,43,204,44): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(204,45,204,46): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(207,28,207,29): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(207,31,207,32): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(207,20,207,35): typecheck error FS3388: This expression implicitly converts type 'R' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(210,22,210,41): typecheck error FS3388: This expression implicitly converts type 'R' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(210,30,210,31): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(210,33,210,34): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(213,29,213,30): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(213,32,213,33): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(213,20,213,36): typecheck error FS3388: This expression implicitly converts type 'SR' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(216,22,216,43): typecheck error FS3388: This expression implicitly converts type 'SR' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(216,31,216,32): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(216,34,216,35): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(219,20,219,33): typecheck error FS3388: This expression implicitly converts type 'U' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(219,20,219,33): typecheck error FS3388: This expression implicitly converts type 'U' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(222,21,222,31): typecheck error FS3388: This expression implicitly converts type 'U' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(225,21,225,31): typecheck error FS3388: This expression implicitly converts type 'int -> U' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(228,21,228,40): typecheck error FS3388: This expression implicitly converts type 'SU' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(228,21,228,40): typecheck error FS3388: This expression implicitly converts type 'SU' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(231,21,231,37): typecheck error FS3388: This expression implicitly converts type 'SU' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(234,21,234,37): typecheck error FS3388: This expression implicitly converts type 'int -> SU' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(237,13,237,14): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(237,16,237,19): typecheck error FS3388: This expression implicitly converts type 'byte' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(237,30,237,33): typecheck error FS3388: This expression implicitly converts type 'float' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(237,35,237,36): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(243,42,243,43): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(246,45,246,46): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(246,54,246,57): typecheck error FS3388: This expression implicitly converts type 'float' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(246,65,246,68): typecheck error FS3388: This expression implicitly converts type 'byte' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(248,49,248,50): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(248,51,248,52): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(253,36,253,37): typecheck error FS3388: This expression implicitly converts type 'int' to type 'IComparable'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(256,30,256,39): typecheck error FS3388: This expression implicitly converts type 'uint16 []' to type 'Array'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(258,30,258,38): typecheck error FS3388: This expression implicitly converts type ''a []' to type 'Array'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(260,36,260,38): typecheck error FS3388: This expression implicitly converts type 'Numerics.BigInteger' to type 'IComparable'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(263,44,263,63): typecheck error FS3388: This expression implicitly converts type 'string' to type 'IComparable'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(275,35,275,36): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(275,37,275,38): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(276,35,276,40): typecheck error FS3388: This expression implicitly converts type 'string' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(276,41,276,42): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(277,44,277,45): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(278,44,278,45): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(278,55,278,58): typecheck error FS3388: This expression implicitly converts type 'float' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(279,68,279,71): typecheck error FS3388: This expression implicitly converts type 'float' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(280,82,280,85): typecheck error FS3388: This expression implicitly converts type 'float' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(282,21,282,22): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(283,22,283,29): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(284,21,284,23): typecheck error FS3388: This expression implicitly converts type 'string' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(285,22,285,33): typecheck error FS3388: This expression implicitly converts type 'string' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(286,22,286,45): typecheck error FS3388: This expression implicitly converts type 'IComparable' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(286,22,286,24): typecheck error FS3388: This expression implicitly converts type 'string' to type 'IComparable'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(287,22,287,24): typecheck error FS3388: This expression implicitly converts type 'string' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(288,22,288,24): typecheck error FS3388: This expression implicitly converts type 'string' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(289,21,289,76): typecheck error FS3388: This expression implicitly converts type 'ICloneable' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(290,21,290,23): typecheck error FS3388: This expression implicitly converts type 'string' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(291,21,291,30): typecheck error FS3388: This expression implicitly converts type 'string' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(291,21,291,30): typecheck error FS3388: This expression implicitly converts type 'string' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(292,24,292,26): typecheck error FS3388: This expression implicitly converts type 'string' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(295,34,295,35): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(295,41,295,44): typecheck error FS3388: This expression implicitly converts type 'float' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(296,35,296,36): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(296,42,296,45): typecheck error FS3388: This expression implicitly converts type 'float' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(297,35,297,36): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(297,52,297,55): typecheck error FS3388: This expression implicitly converts type 'byte' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(297,61,297,64): typecheck error FS3388: This expression implicitly converts type 'float' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(300,25,300,26): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(300,37,300,40): typecheck error FS3388: This expression implicitly converts type 'float' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(303,25,303,26): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(306,45,306,46): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(306,54,306,57): typecheck error FS3388: This expression implicitly converts type 'float' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(309,19,309,20): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(310,32,310,33): typecheck error FS3388: This expression implicitly converts type 'int' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(310,39,310,42): typecheck error FS3388: This expression implicitly converts type 'float' to type 'obj'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(313,37,313,38): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(313,37,313,38): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(314,37,314,38): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(314,37,314,38): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(317,50,317,51): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(317,50,317,51): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(319,52,319,53): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(319,52,319,53): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(320,37,320,38): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(320,37,320,38): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(323,57,323,58): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(323,57,323,58): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(325,57,325,58): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(325,57,325,58): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(326,37,326,38): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(326,37,326,38): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(328,42,328,43): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(328,42,328,43): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(330,42,330,43): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(330,42,330,43): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(331,38,331,39): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(331,38,331,39): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(335,28,335,39): typecheck error FS3388: This expression implicitly converts type 'int64 list' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(335,36,335,37): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(335,36,335,37): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(337,9,338,34): typecheck error FS3388: This expression implicitly converts type 'int64 list' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(337,17,337,18): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(337,17,337,18): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(340,9,341,33): typecheck error FS3388: This expression implicitly converts type 'int64 list' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(341,30,341,31): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(341,30,341,31): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(343,9,344,35): typecheck error FS3388: This expression implicitly converts type 'int64 list' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(344,32,344,33): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(344,32,344,33): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(346,9,347,36): typecheck error FS3388: This expression implicitly converts type 'int64 list' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(346,17,346,18): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(346,17,346,18): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(349,9,349,36): typecheck error FS3388: This expression implicitly converts type 'int64 list' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(351,9,351,40): typecheck error FS3388: This expression implicitly converts type 'int64 list' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(351,37,351,38): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(351,37,351,38): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(353,9,354,40): typecheck error FS3388: This expression implicitly converts type 'int64 list' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(354,37,354,38): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(354,37,354,38): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(356,9,357,41): typecheck error FS3388: This expression implicitly converts type 'int64 list' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(356,17,356,18): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(356,17,356,18): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(359,9,359,35): typecheck error FS3388: This expression implicitly converts type 'int64 list' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(359,21,359,22): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(359,21,359,22): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(361,9,362,36): typecheck error FS3388: This expression implicitly converts type 'int64 list' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(362,21,362,22): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(362,21,362,22): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(364,9,365,37): typecheck error FS3388: This expression implicitly converts type 'int64 list' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(364,17,364,18): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(364,17,364,18): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(368,39,368,40): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(368,39,368,40): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(369,39,369,40): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(369,39,369,40): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(372,52,372,53): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(372,52,372,53): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(374,54,374,55): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(374,54,374,55): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(375,39,375,40): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(375,39,375,40): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(378,59,378,60): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(378,59,378,60): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(380,59,380,60): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(380,59,380,60): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(381,39,381,40): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(381,39,381,40): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(383,44,383,45): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(383,44,383,45): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(385,44,385,45): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(385,44,385,45): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(386,40,386,41): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(386,40,386,41): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(390,28,390,41): typecheck error FS3388: This expression implicitly converts type 'int64 []' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(390,37,390,38): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(390,37,390,38): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(391,30,392,57): typecheck error FS3388: This expression implicitly converts type 'int64 []' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(391,39,391,40): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(391,39,391,40): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(393,30,394,56): typecheck error FS3388: This expression implicitly converts type 'int64 []' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(394,52,394,53): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(394,52,394,53): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(395,30,396,58): typecheck error FS3388: This expression implicitly converts type 'int64 []' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(396,54,396,55): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(396,54,396,55): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(397,30,398,59): typecheck error FS3388: This expression implicitly converts type 'int64 []' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(397,39,397,40): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(397,39,397,40): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(399,30,399,59): typecheck error FS3388: This expression implicitly converts type 'int64 []' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(400,30,400,63): typecheck error FS3388: This expression implicitly converts type 'int64 []' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(400,59,400,60): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(400,59,400,60): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(401,30,402,63): typecheck error FS3388: This expression implicitly converts type 'int64 []' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(402,59,402,60): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(402,59,402,60): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(403,30,404,64): typecheck error FS3388: This expression implicitly converts type 'int64 []' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(403,39,403,40): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(403,39,403,40): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(405,31,405,59): typecheck error FS3388: This expression implicitly converts type 'int64 []' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(405,44,405,45): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(405,44,405,45): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(406,31,407,60): typecheck error FS3388: This expression implicitly converts type 'int64 []' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(407,44,407,45): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(407,44,407,45): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(408,31,409,61): typecheck error FS3388: This expression implicitly converts type 'int64 []' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(408,40,408,41): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(408,40,408,41): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(429,10,437,16): typecheck error FS3388: This expression implicitly converts type 'OtherSeq' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(448,9,450,49): typecheck error FS3388: This expression implicitly converts type 'OtherSeqImpl' to type 'seq'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(452,32,452,33): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(452,32,452,33): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(454,46,454,47): typecheck error FS3389: This expression uses a built-in implicit conversion to convert type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(454,46,454,47): typecheck error FS3388: This expression implicitly converts type 'int' to type 'int64'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(463,18,463,19): typecheck error FS0001: This expression was expected to have type + 'C' +but here has type + 'int' + +test.fsx(471,18,471,19): typecheck error FS3390: This expression uses the implicit conversion 'static member C.op_Implicit : x:int -> C' to convert type 'int' to type 'C'. + +test.fsx(471,18,471,19): typecheck error FS3388: This expression implicitly converts type 'int' to type 'C'. See https://aka.ms/fsharp-implicit-convs. + +test.fsx(471,18,471,19): typecheck error FS0044: This construct is deprecated. nope + +test.fsx(482,18,482,21): typecheck error FS3387: This expression has type 'B' and is only made compatible with type 'C' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are: + static member B.op_Implicit : x:B -> C + static member C.op_Implicit : x:B -> C + +test.fsx(482,18,482,21): typecheck error FS3391: This expression uses the implicit conversion 'static member B.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(482,18,482,21): typecheck error FS3387: This expression has type 'B' and is only made compatible with type 'C' through an ambiguous implicit conversion. Consider using an explicit call to 'op_Implicit'. The applicable implicit conversions are: + static member B.op_Implicit : x:B -> C + static member C.op_Implicit : x:B -> C + +test.fsx(482,18,482,21): typecheck error FS3391: This expression uses the implicit conversion 'static member B.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(507,18,507,21): typecheck error FS3391: This expression uses the implicit conversion 'static member C.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(507,18,507,21): typecheck error FS3391: This expression uses the implicit conversion 'static member C.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(519,18,519,21): typecheck error FS3391: This expression uses the implicit conversion 'static member B.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(519,18,519,21): typecheck error FS3391: This expression uses the implicit conversion 'static member B.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(538,18,538,21): typecheck error FS3391: This expression uses the implicit conversion 'static member C.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(538,18,538,21): typecheck error FS3391: This expression uses the implicit conversion 'static member C.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3391". + +test.fsx(543,30,543,31): typecheck error FS0001: This expression was expected to have type + 'float32' +but here has type + 'int' + +test.fsx(543,32,543,33): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'float32'. This element has type 'int'. + +test.fsx(543,34,543,35): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'float32'. This element has type 'int'. + +test.fsx(543,36,543,37): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'float32'. This element has type 'int'. + +test.fsx(544,14,544,21): typecheck error FS0039: The type 'float64' is not defined. Maybe you want one of the following: + float + float`1 + float32 + float32`1 diff --git a/tests/fsharp/core/auto-widen/preview/test.fsx b/tests/fsharp/core/auto-widen/preview/test.fsx new file mode 100644 index 00000000000..548f9081db6 --- /dev/null +++ b/tests/fsharp/core/auto-widen/preview/test.fsx @@ -0,0 +1,557 @@ + +#r "System.Xml.Linq.dll" +#r "System.Xml.XDocument.dll" + +let mutable failures : string list = [] + +open System + +module BasicTypeDirectedConversionsToObj = + // Constant expression + let x1 : obj = 1 + + // Field literal expressions + let x2 : obj = System.Int32.MaxValue + + // Field literal expressions + let x3 : obj = System.Int32.Parse("12") + + // Tuple expressions + let x4 : obj = (1,2) + + // Arithmetic expressions + // These do NOT permit type-directed subsumption nor widening because a generic return type is involved + // the is not yet committed + // let x : obj = 1 + 1 + + // Values + let x8 (s:string) : obj = s + +module BasicTypeDirectedConversionsToTuple = + + // Tuple expressions + let x2 : obj * obj = (1,2) + + // Let expressions + let x3 : (obj * obj) = (let x = 1 in let y = 2 in (x,y)) + + // Struct tuple expressions + let x4 : struct (obj * obj) = struct (1,2) + +module BasicTypeDirectedConversionsForFuncReturn = + + // Return in lambda expressions + let x5 : (unit -> obj) = (fun () -> 1) + let x6 : (unit -> obj * obj) = (fun () -> (1,2)) + + // Return in function expressions + let x7 () : obj * obj = (1,2) + +type R = { mutable F1: (obj * obj) } +[] +type SR = { mutable SF1: (obj * obj) } +type U = UnionCase0 | UnionCase1 of int +[] +type SU = StructUnionCase0 | StructUnionCase1 of int +module IntegerWidening = + let i1 = 0 + let x0 : int64 = i1 // integer value + let x1 : int64 = 0 // integer constant + let x2 : int64 list = [1;2;3;4] // within a list + let x3 : float list = [1;2;3;4.0] + //let x4 : float32 list = [1;2;3;4] + let x5 : int64 = System.Int32.MaxValue + let x6 : int64 list = [System.Int32.MaxValue;System.Int32.MaxValue] + let f () = 1 + + let x7 : obj = f() + let x8 : int64 = f() + let x9 : int64 = id (f()) // generic does work + + // Arithmetic expressions + // These do NOT permit type-directed subsumption nor widening because a generic return type is involved + // the is not yet committed + // let x6 : int64 = 1 + 1 + // let x6 : int64 = id (1 + 1) + +module Overloads1 = + type C() = + static member M1(x:int) = 1 + static member M1(x:int64) = failwith "nope" + let x = C.M1(2) + +module Overloads2 = + type C() = + static member M1(x:int) = failwith "nope" + static member M1(x:int64) = printfn "ok at line %s" __LINE__ + let x = C.M1(2L) + +module Overloads3 = + type C() = + static member M1(x:string) = failwith "nope" + static member M1(x:int64) = printfn "ok at line %s" __LINE__ + let x = C.M1(2) + +module OverloadedOptionals1 = + type C() = + static member M1(x:string) = failwith "nope" + static member M1(?x:int64) = printfn "ok at line %s" __LINE__ + let x = C.M1(x=2) + +module OverloadedOptionals2 = + type C() = + static member M1(?x:int) = printfn "ok at line %s" __LINE__ + static member M1(?x:int64) = failwith "nope" + let x = C.M1(x=2) + +module OverloadedOptionals3 = + type C() = + static member M1(?x:int) = failwith "nope" + static member M1(?x:int64) = printfn "ok at line %s" __LINE__ + let x = C.M1(x=2L) + +module Optionals1 = + type C() = + static member M1(?x:int64) = 1 + let x = C.M1(x=2) + +module ParamArray1 = + type C() = + static member M1([] x:int64[]) = Array.sum x + let x1 = C.M1(2) + let x2 = C.M1(2, 3, 5L) + +module ParamArray2 = + type C() = + static member M1([] x:double[]) = Array.sum x + let x1 = C.M1(2) + let x2 = C.M1(2, 3, 5.0) + +module ConvertToSealedViaOpImplicit = + [] + type C() = + static member op_Implicit(x:int) = C() + static member M1(C:C) = 1 + let x = C.M1(2) + +module ConvertNoOverloadin = + type C() = + static member M1(x:int64) = 1 + let x = C.M1(2) + +module ConvertNoOverloadingViaOpImplicit = + type C() = + static member M1(x:decimal) = () + let x = C.M1(2) + +let d: decimal = 3 + +let ns : System.Xml.Linq.XNamespace = "" + +module ConvertViaOpImplicit2 = + type C() = + static member M1(ns:System.Xml.Linq.XNamespace) = 1 + let x = C.M1("") + +module ConvertViaOpImplicit3 = + type C() = + static member M1(ns:System.Xml.Linq.XName) = 1 + let x = C.M1("a") + +module ConvertViaOpImplicit4 = + type C() = + static member op_Implicit(x:int) = C() + static member M1(C:C) = 1 + let x = C.M1(2) + +module ConvertViaOpImplicit5 = + type X() = + static member M1(x:X) = 1 + type Y() = + static member op_Implicit(y:Y) = X() + let x = X.M1(Y()) + +module ConvertViaOpImplicitGeneric = + type C<'T>() = + static member op_Implicit(x: 'T) = C<'T>() + + let c:C = 1 + let f (c:C) = 1 + let x = f 2 + +module ConvertViaNullable = + type C<'T>() = + static member op_Implicit(x: 'T) = C<'T>() + + let c:Nullable = 1 + let f (c:Nullable) = 1 + let x = f 2 + +let annotations = + let v1 : obj = (1,2) + let v2 : obj * obj = (1,2) + + // structure through let + let v3 : (obj * obj) = (let x = 1 in let y = 2 in (x,y)) + + // structure through let rec + let v4 : (obj * obj) = (let rec f x = x in (3,4.0)) + + // structure through sequence + let v5 : (obj * obj) = (); (3,4.0) + + // struct tuple + let v6 : struct (obj * obj) = struct (1,2) + + // record (both field and overall result) + let v7 : obj = { F1 = (1, 2) } + + // record + let v7a : obj = ({ F1 = (1, 2) } : R) + + // struct record (both field and overall result) + let v8 : obj = { SF1 = (1, 2) } + + // struct record (both field and overall result) + let v8a : obj = ({ SF1 = (1, 2) } : SR) + + // union + let v9 : obj = UnionCase1(3) + + // union + let v10 : obj = UnionCase0 + + // union as first-class + let v11 : obj = UnionCase1 + + // struct union + let v12 : obj = StructUnionCase1(3) + + // struct union + let v13 : obj = StructUnionCase0 + + // struct union as first-class + let v14 : obj = StructUnionCase1 + + // record (both field and overall result) + { F1 = (1, 2uy) }.F1 <- (3.0, 4) + + // anon record + let v15 : {| A: obj |} = {| A = 1 |} + + // lambda return + let v16 : (unit -> obj) = (fun () -> 1) + + // function lambda return + let v17 : (int -> obj) = (function 1 -> 1 | 2 -> 3.0 | _ -> 4uy) + + let v18 : (unit -> obj * obj) = (fun () -> (1,2)) + + // constants + (1 :> System.IComparable) |> ignore + + let v19 : System.IComparable = 1 + + // array constants + let v20 : System.Array = [| 1us |] + + let v21 : System.Array = [| 1I |] + + let v22 : System.IComparable = 1I + + // property + let v23 : System.IComparable = System.String.Empty + + // method + let v24 : System.IComparable = System.String.Format("") + + let v25 : obj = System.String.Format("") + + let v26 : System.IComparable = System.String.Format("") + + // array constants + + let v27 : obj[] = [| 1 |] + let v28 : (obj * obj)[] = [| (1,1) |] + let v29 : (obj * obj)[] = [| ("abc",1) |] + let v30 : (string * obj)[] = [| ("abc",1) |] + let v31 : (string * obj)[] = [| ("abc",1); ("abc",3.0) |] + let v32 : (string * obj)[] = [| Unchecked.defaultof<_>; ("abc",3.0) |] + let v33 : struct (string * obj)[] = [| Unchecked.defaultof<_>; struct ("abc",3.0) |] + + let v34 : obj = 1 + let v35 : obj = (1 : int) + let v36 : obj = "" + let v37 : obj = ("" : string) + let v38 : obj = ("" : System.IComparable) + let v39 : obj = ("" : _) + let v40 : obj = ("" : obj) + let v41 : obj = { new System.ICloneable with member x.Clone() = obj() } + let v42 : obj = "" + let v43 : obj = string "" + let v44 : obj = id "" + + // conditional + let v45 : obj = if true then 1 else 3.0 + let v46 : obj = (if true then 1 else 3.0) + let v47 : obj = (if true then 1 elif true then 2uy else 3.0) + + // try-with + let v48 : obj = try 1 with _ -> 3.0 + + // try-finally + let v49 : obj = try 1 finally () + + // match + let v50 : obj = match true with true -> 1 | _ -> 3.0 + () + +let f1 () : obj = 1 +let f2 () : obj = if true then 1 else 3.0 + +module TestComputedListExpressionsAtList = + let x1 : list = [ yield 1 ] + let x2 : list = [ yield 1; + if true then yield 2L ] + let x3 : list = [ yield 1L; + if true then yield 2 ] + let x4 : list = [ yield 1L; + while false do yield 2 ] + let x5 : list = [ yield 1; + while false do yield 2L ] + let x6 : list = [ while false do yield 2L ] + let x7 : list = [ for i in 0 .. 10 do yield 2 ] + let x8 : list = [ yield 1L + for i in 0 .. 10 do yield 2 ] + let x9 : list = [ yield 1 + for i in 0 .. 10 do yield 2L ] + let x10 : list = [ try yield 2 finally () ] + let x11 : list = [ yield 1L + try yield 2 finally () ] + let x12 : list = [ yield 1 + try yield 2L finally () ] + +module TestComputedListExpressionsAtSeq = + let x1 : seq = [ yield 1 ] + let x2 : seq = + [ yield 1; + if true then yield 2L ] + let x3 : seq = + [ yield 1L; + if true then yield 2 ] + let x4 : seq = + [ yield 1L; + while false do yield 2 ] + let x5 : seq = + [ yield 1; + while false do yield 2L ] + let x6 : seq = + [ while false do yield 2L ] + let x7 : seq = + [ for i in 0 .. 10 do yield 2 ] + let x8 : seq = + [ yield 1L + for i in 0 .. 10 do yield 2 ] + let x9 : seq = + [ yield 1 + for i in 0 .. 10 do yield 2L ] + let x10 : seq = + [ try yield 2 finally () ] + let x11 : seq = + [ yield 1L + try yield 2 finally () ] + let x12 : seq = + [ yield 1 + try yield 2L finally () ] + +module TestComputedArrayExpressionsAtArray = + let x1 : array = [| yield 1 |] + let x2 : array = [| yield 1; + if true then yield 2L |] + let x3 : array = [| yield 1L; + if true then yield 2 |] + let x4 : array = [| yield 1L; + while false do yield 2 |] + let x5 : array = [| yield 1; + while false do yield 2L |] + let x6 : array = [| while false do yield 2L |] + let x7 : array = [| for i in 0 .. 10 do yield 2 |] + let x8 : array = [| yield 1L + for i in 0 .. 10 do yield 2 |] + let x9 : array = [| yield 1 + for i in 0 .. 10 do yield 2L |] + let x10 : array = [| try yield 2 finally () |] + let x11 : array = [| yield 1L + try yield 2 finally () |] + let x12 : array = [| yield 1 + try yield 2L finally () |] + +module TestComputedArrayExpressionsAtSeq = + let x1 : seq = [| yield 1 |] + let x2 : seq = [| yield 1; + if true then yield 2L |] + let x3 : seq = [| yield 1L; + if true then yield 2 |] + let x4 : seq = [| yield 1L; + while false do yield 2 |] + let x5 : seq = [| yield 1; + while false do yield 2L |] + let x6 : seq = [| while false do yield 2L |] + let x7 : seq = [| for i in 0 .. 10 do yield 2 |] + let x8 : seq = [| yield 1L + for i in 0 .. 10 do yield 2 |] + let x9 : seq = [| yield 1 + for i in 0 .. 10 do yield 2L |] + let x10 : seq = [| try yield 2 finally () |] + let x11 : seq = [| yield 1L + try yield 2 finally () |] + let x12 : seq = [| yield 1 + try yield 2L finally () |] + +module TestInferObjExprTypeParamFromKNownType = + // Check we are inferring type int64 + let x1 : seq = + { new seq<_> with + member x.GetEnumerator() = + // The 'ToString("4")' would not resolve if the type parameter is not inferred by this point + x.GetEnumerator().Current.ToString("4") |> ignore + failwith "" + + interface System.Collections.IEnumerable with + member x.GetEnumerator() = failwith "" + } + + type OtherSeq<'T> = + inherit seq<'T> + + // Check we are inferring type int64 + let x2 : seq = + { new OtherSeq<_> with + member x.GetEnumerator() = + // The 'ToString("4")' would not resolve if the type parameter is not inferred by this point + x.GetEnumerator().Current.ToString("4") |> ignore + failwith "" + + interface System.Collections.IEnumerable with + member x.GetEnumerator() = failwith "" + } + + type OtherSeqImpl<'T>(f : 'T -> unit) = + interface OtherSeq<'T> with + member x.GetEnumerator() = + failwith "" + + interface System.Collections.IEnumerable with + member x.GetEnumerator() = failwith "" + + let x3 : seq = + new OtherSeqImpl<_>(fun x -> + // The 'ToString("4")' would not resolve if the type parameter is not inferred to be int64 by this point + x.ToString("4") |> ignore) + + let x4 : int64 * int32 = (3, 3) + + let x5 : {| A: int64; B: int32 |} = {| A=3; B=3 |} + +// These tests are activate for the case where warnings are on +#if NEGATIVE +module TestAcessibilityOfOpImplicit = + [] + type C() = + static member private op_Implicit(x:int) = C() + static member M1(C:C) = 1 + let x = C.M1(2) + +module TestObsoleteOfOpImplicit = + [] + type C() = + [] + static member op_Implicit(x:int) = C() + static member M1(C:C) = 1 + let x = C.M1(2) + +module TestAmbiguousOpImplicit = + [] + type B() = + static member op_Implicit(x:B) = C(2) + + and [] C(x:int) = + static member op_Implicit(x:B) = C(1) + static member M1(C:C) = 1 + member _.Value = x + let x = C.M1(B()) + +#endif + +let report_failure (s : string) = + stderr.Write" NO: " + stderr.WriteLine s + failures <- failures @ [s] + +let test (s : string) b = + stderr.Write(s) + if b then stderr.WriteLine " OK" + else report_failure (s) + +let check s b1 b2 = test s (b1 = b2) + +module TestAmbiguousOpImplicitOkOneIsPrivate = + [] + type B() = + static member private op_Implicit(x:B) = C(1) + + and [] C(x:int) = + static member op_Implicit(x:B) = C(2) + static member M1(c:C) = c.Value + member _.Value = x + let x = C.M1(B()) + check "vewenlwevl" x 2 + +module TestAmbiguousOpImplicitOkOtherIsPrivate = + [] + type B() = + static member op_Implicit(x:B) = C(1) + + and [] C(x:int) = + static member private op_Implicit(x:B) = C(2) + static member M1(c:C) = c.Value + member _.Value = x + let x = C.M1(B()) + check "vewenlwevl" x 1 + +#nowarn "1215" +module TestExtrinsicOpImplicitIgnoredCompletely = + [] + type B() = class end + + and [] C(x:int) = + static member op_Implicit(x:B) = C(3) + static member M1(c:C) = c.Value + member _.Value = x + + [] + module Extensions = + type B with + // This gets ignored - a warning 1215 is actually reported implying this (ignored above) + static member op_Implicit(x:B) = C(1) + + let x = C.M1(B()) + check "vewenlwevlce" x 3 + +#if NEGATIVE +module TestNoWidening = + let x4 : float32 list = [1;2;3;4] + let x5 : float64 list = [1.0f;2.0f;3.0f;4.0f] +#endif +printfn "test done" + +let aa = + match failures with + | [] -> + stdout.WriteLine "Test Passed" + System.IO.File.WriteAllText("test.ok","ok") + exit 0 + | _ -> + printfn "Test Failed, failures = %A" failures + exit 1 + diff --git a/tests/fsharp/tests.fs b/tests/fsharp/tests.fs index c310593cbe9..b80540568b3 100644 --- a/tests/fsharp/tests.fs +++ b/tests/fsharp/tests.fs @@ -70,6 +70,31 @@ module CoreTests = [] let ``array-FSI_BASIC`` () = singleTestBuildAndRun "core/array" FSI_BASIC + [] + let ``auto-widen-version-5_0``() = + let cfg = testConfig "core/auto-widen/5.0" + singleVersionedNegTest cfg "5.0" "test" + + [] + let ``auto-widen-version-FSC_BASIC_OPT_MINUS-preview``() = + singleTestBuildAndRunVersion "core/auto-widen/preview" FSC_BASIC_OPT_MINUS "preview" + + [] + let ``auto-widen-version-FSC_BASIC-preview``() = + singleTestBuildAndRunVersion "core/auto-widen/preview" FSC_BASIC "preview" + + [] + let ``auto-widen-version-preview-warns-on``() = + let cfg = testConfig "core/auto-widen/preview" + let cfg = { cfg with fsc_flags = cfg.fsc_flags + " --warnon:3388 --warnon:3389 --warnon:3390 --warnaserror+ --define:NEGATIVE" } + singleVersionedNegTest cfg "preview" "test" + + [] + let ``auto-widen-version-preview-default-warns``() = + let cfg = testConfig "core/auto-widen/preview-default-warns" + let cfg = { cfg with fsc_flags = cfg.fsc_flags + " --warnaserror+ --define:NEGATIVE" } + singleVersionedNegTest cfg "preview" "test" + [] let ``comprehensions-FSC_BASIC_OPT_MINUS`` () = singleTestBuildAndRun "core/comprehensions" FSC_BASIC_OPT_MINUS @@ -1012,35 +1037,35 @@ module CoreTests = | diffs -> Assert.Fail (sprintf "'%s' and '%s' differ; %A" diffFileErr expectedFileErr diffs) [] - let ``printing-1 --langversion:4.7`` () = + let ``printing-1 --langversion:4_7`` () = printing "--langversion:4.7" "z.output.test.default.stdout.47.txt" "z.output.test.default.stdout.47.bsl" "z.output.test.default.stderr.txt" "z.output.test.default.stderr.bsl" [] - let ``printing-1 --langversion:5.0`` () = + let ``printing-1 --langversion:5_0`` () = printing "--langversion:5.0" "z.output.test.default.stdout.50.txt" "z.output.test.default.stdout.50.bsl" "z.output.test.default.stderr.txt" "z.output.test.default.stderr.bsl" [] - let ``printing-2 --langversion:4.7`` () = + let ``printing-2 --langversion:4_7`` () = printing "--langversion:4.7 --use:preludePrintSize1000.fsx" "z.output.test.1000.stdout.47.txt" "z.output.test.1000.stdout.47.bsl" "z.output.test.1000.stderr.txt" "z.output.test.1000.stderr.bsl" [] - let ``printing-2 --langversion:5.0`` () = + let ``printing-2 --langversion:5_0`` () = printing "--langversion:5.0 --use:preludePrintSize1000.fsx" "z.output.test.1000.stdout.50.txt" "z.output.test.1000.stdout.50.bsl" "z.output.test.1000.stderr.txt" "z.output.test.1000.stderr.bsl" [] - let ``printing-3 --langversion:4.7`` () = + let ``printing-3 --langversion:4_7`` () = printing "--langversion:4.7 --use:preludePrintSize200.fsx" "z.output.test.200.stdout.47.txt" "z.output.test.200.stdout.47.bsl" "z.output.test.200.stderr.txt" "z.output.test.200.stderr.bsl" [] - let ``printing-3 --langversion:5.0`` () = + let ``printing-3 --langversion:5_0`` () = printing "--langversion:5.0 --use:preludePrintSize200.fsx" "z.output.test.200.stdout.50.txt" "z.output.test.200.stdout.50.bsl" "z.output.test.200.stderr.txt" "z.output.test.200.stderr.bsl" [] - let ``printing-4 --langversion:4.7`` () = + let ``printing-4 --langversion:4_7`` () = printing "--langversion:4.7 --use:preludeShowDeclarationValuesFalse.fsx" "z.output.test.off.stdout.47.txt" "z.output.test.off.stdout.47.bsl" "z.output.test.off.stderr.txt" "z.output.test.off.stderr.bsl" [] - let ``printing-4 --langversion:5.0`` () = + let ``printing-4 --langversion:5_0`` () = printing "--langversion:5.0 --use:preludeShowDeclarationValuesFalse.fsx" "z.output.test.off.stdout.50.txt" "z.output.test.off.stdout.50.bsl" "z.output.test.off.stderr.txt" "z.output.test.off.stderr.bsl" [] @@ -2614,6 +2639,11 @@ module TypecheckTests = [] let ``type check neg20`` () = singleNegTest (testConfig "typecheck/sigs") "neg20" + [] + let ``type check neg20 version 5_0`` () = + let cfg = testConfig "typecheck/sigs/version50" + singleVersionedNegTest cfg "5.0" "neg20" + [] let ``type check neg21`` () = singleNegTest (testConfig "typecheck/sigs") "neg21" @@ -2635,6 +2665,13 @@ module TypecheckTests = let cfg = testConfig "typecheck/sigs/version47" // For some reason this warning is off by default in the test framework but in this case we are testing for it let cfg = { cfg with fsc_flags = cfg.fsc_flags.Replace("--nowarn:20", "") } + singleVersionedNegTest cfg "4.7" "neg24" + + [] + let ``type check neg24 version preview`` () = + let cfg = testConfig "typecheck/sigs" + // For some reason this warning is off by default in the test framework but in this case we are testing for it + let cfg = { cfg with fsc_flags = cfg.fsc_flags.Replace("--nowarn:20", "") } singleVersionedNegTest cfg "preview" "neg24" [] diff --git a/tests/fsharp/typecheck/sigs/neg20.bsl b/tests/fsharp/typecheck/sigs/neg20.bsl index 75d06ce1332..810220f0590 100644 --- a/tests/fsharp/typecheck/sigs/neg20.bsl +++ b/tests/fsharp/typecheck/sigs/neg20.bsl @@ -69,17 +69,17 @@ neg20.fs(53,38,53,39): typecheck error FS0001: This expression was expected to h but here has type 'int' -neg20.fs(60,26,60,33): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'B'. This element has type 'A'. +neg20.fs(60,26,60,33): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'B'. This element has type 'A'. -neg20.fs(61,27,61,35): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'B1'. This element has type 'B2'. +neg20.fs(61,27,61,35): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'B1'. This element has type 'B2'. -neg20.fs(62,26,62,33): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'C'. This element has type 'B'. +neg20.fs(62,26,62,33): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'C'. This element has type 'B'. -neg20.fs(66,25,66,32): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'A'. This element has type 'B'. +neg20.fs(66,25,66,32): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'A'. This element has type 'B'. -neg20.fs(67,27,67,34): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'B'. This element has type 'C'. +neg20.fs(67,27,67,34): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'B'. This element has type 'C'. -neg20.fs(70,31,70,38): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'B'. This element has type 'C'. +neg20.fs(70,31,70,38): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'B'. This element has type 'C'. neg20.fs(71,34,71,42): typecheck error FS0001: Type mismatch. Expecting a 'A list' @@ -110,9 +110,9 @@ but given a 'B list' The type 'A' does not match the type 'B' -neg20.fs(83,47,83,54): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'B'. This branch returns a value of type 'C'. +neg20.fs(83,47,83,54): typecheck error FS0001: All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is 'B'. This branch returns a value of type 'C'. -neg20.fs(87,54,87,61): typecheck error FS0001: All branches of a pattern match expression must return values of the same type as the first branch, which here is 'B'. This branch returns a value of type 'C'. +neg20.fs(87,54,87,61): typecheck error FS0001: All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is 'B'. This branch returns a value of type 'C'. neg20.fs(92,19,92,26): typecheck error FS0001: This expression was expected to have type 'A' @@ -129,7 +129,7 @@ neg20.fs(97,26,97,33): typecheck error FS0001: This expression was expected to h but here has type 'B' -neg20.fs(99,26,99,33): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'B'. This element has type 'A'. +neg20.fs(99,26,99,33): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'B'. This element has type 'A'. neg20.fs(108,12,108,16): typecheck error FS0001: Type mismatch. Expecting a 'B * B -> 'a' @@ -415,3 +415,13 @@ neg20.fs(428,19,428,38): typecheck error FS1133: No constructors are available f neg20.fs(430,22,430,41): typecheck error FS1133: No constructors are available for the type 'OverloadedClassName<'a,'b>' neg20.fs(444,39,444,41): typecheck error FS0039: The type 'OverloadedClassName' does not define the field, constructor or member 'S2'. + +neg20.fs(447,27,447,28): typecheck error FS0001: This expression was expected to have type + 'int option' +but here has type + 'int' + +neg20.fs(448,30,448,33): typecheck error FS0001: This expression was expected to have type + 'string option' +but here has type + 'string' diff --git a/tests/fsharp/typecheck/sigs/neg20.fs b/tests/fsharp/typecheck/sigs/neg20.fs index 5d465aeea93..4b0a08e0033 100644 --- a/tests/fsharp/typecheck/sigs/neg20.fs +++ b/tests/fsharp/typecheck/sigs/neg20.fs @@ -49,7 +49,7 @@ module BiGenericFunctionTests = module NoSubsumptionOnApplication = - (fun (x:A) -> 1) (new B()) // no: subsumption comes from de-condensation, not application! + (fun (x:A) -> 1) (new B()) // now permitted (fun (x:System.ValueType) -> 1) 1 // coercion on application! @@ -73,7 +73,7 @@ module NoSubsumptionForLists = // Q: how about on sequence expressions? let controls2 = [ yield (new B()) yield (new C()) ] - StaticClass2.DisplayControls controls2 // bang + StaticClass2.DisplayControls controls2 // Q: how about on sequence expressions? let controls3 = [ yield! [new B()] @@ -81,14 +81,14 @@ module NoSubsumptionForLists = StaticClass2.DisplayControls controls3 // bang let controls4 = if true then new B() else new C() - StaticClass2.DisplayControls [controls4] // bang + StaticClass2.DisplayControls [controls4] // allowed - // Q: how about on matches? Not covered. Decision: disallow + // Q: how about on matches? allowed let controls5 = match 1 with 1 -> new B() | _ -> new C() - StaticClass2.DisplayControls [controls5] // bang + StaticClass2.DisplayControls [controls5] // allowed - // Q. subsumption on 'let v = expr'? Not covered. Disallow + // Q. subsumption on 'let v = expr'? Allowed let x76 : A = new B() module NoSubsumptionForLists2 = @@ -126,7 +126,7 @@ module BiGenericMethodsInGenericClassTests = let str = "" C.M3("a",obj) // this is not permitted since 'b is inferred to be "string". Fair enough - C.M3(obj,"a") + C.M3(obj,"a") // now permitted C.OM3("a",obj) // this is not permitted since 'b is inferred to be "string". Fair enough @@ -443,3 +443,7 @@ module OverloadedTypeNamesIncludingNonGenericTypeNoConstructors = let t3 = 3 |> OverloadedClassName.S // NO ERROR EXPECTED let t4 = 3 |> OverloadedClassName.S2 // expected error - The field, constructor or member 'S2' is not defined +module OptionTypeOpImplicitsIgnored = + let x1 : int option = 3 + let x2 : string option = "a" + diff --git a/tests/fsharp/typecheck/sigs/neg24.bsl b/tests/fsharp/typecheck/sigs/neg24.bsl new file mode 100644 index 00000000000..03d8ce84002 --- /dev/null +++ b/tests/fsharp/typecheck/sigs/neg24.bsl @@ -0,0 +1,40 @@ + +neg24.fs(53,24,53,30): typecheck error FS0816: One or more of the overloads of this method has curried arguments. Consider redesigning these members to take arguments in tupled form. + +neg24.fs(55,31,55,37): typecheck error FS0816: One or more of the overloads of this method has curried arguments. Consider redesigning these members to take arguments in tupled form. + +neg24.fs(57,38,57,42): typecheck error FS0816: One or more of the overloads of this method has curried arguments. Consider redesigning these members to take arguments in tupled form. + +neg24.fs(60,24,60,34): typecheck error FS0816: One or more of the overloads of this method has curried arguments. Consider redesigning these members to take arguments in tupled form. + +neg24.fs(62,31,62,41): typecheck error FS0816: One or more of the overloads of this method has curried arguments. Consider redesigning these members to take arguments in tupled form. + +neg24.fs(64,44,64,48): typecheck error FS0816: One or more of the overloads of this method has curried arguments. Consider redesigning these members to take arguments in tupled form. + +neg24.fs(70,15,70,18): typecheck error FS0495: The member or object constructor 'M' has no argument or settable return property 'qez'. The required signature is member C.M : abc:int * def:string -> int. + +neg24.fs(300,29,300,30): typecheck error FS0020: The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'. + +neg24.fs(301,17,301,18): typecheck error FS0020: The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'. + +neg24.fs(302,33,302,34): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'unit'. This element has type 'int'. + +neg24.fs(302,36,302,37): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'unit'. This element has type 'int'. + +neg24.fs(304,11,305,32): typecheck error FS0193: Type constraint mismatch. The type + 'int' +is not compatible with type + 'unit' + + +neg24.fs(308,30,308,31): typecheck error FS0020: The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'. + +neg24.fs(309,31,309,32): typecheck error FS0001: This 'if' expression is missing an 'else' branch. Because 'if' is an expression, and not a statement, add an 'else' branch which also returns a value of type 'int'. + +neg24.fs(312,33,312,34): typecheck error FS0020: The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'. + +neg24.fs(313,38,313,39): typecheck error FS0020: The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'. + +neg24.fs(313,47,313,48): typecheck error FS0020: The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'. + +neg24.fs(337,37,337,42): typecheck error FS0020: The result of this expression has type 'obj' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'. diff --git a/tests/fsharp/typecheck/sigs/neg24.fs b/tests/fsharp/typecheck/sigs/neg24.fs new file mode 100644 index 00000000000..38cb01cf2d2 --- /dev/null +++ b/tests/fsharp/typecheck/sigs/neg24.fs @@ -0,0 +1,339 @@ +module Test +open Microsoft.FSharp.Quotations + + +let test2 (v : Expr<'a> -> Expr<'b>) = <@ fun (i: 'a) -> %v <@i@> @> + +let test (v : 'a -> Expr<'b>) = <@ fun (i: 'a) -> %(v i) @> + + +module OldNegative = + let v1 = [ if true then 1 else 2 ] // no longer an error or warning + let v2 = [ if true then () else () ] // no longer an error or warning + let v6 = [ if true then () ] // no longer an error or warning + let a1 = [| if true then 1 else 2 |] // no longer an error or warning + let a2 = [| if true then () else () |] // no longer an error or warning + let a6 = [| if true then () |] // no longer an error or warning + let s3 = seq { (if true then 1 else 2) } // no longer an error or warning + +// expect no warning +module Positive = + let v3 = [ (if true then 1 else 2) ] + let v4 = [ if true then yield 1 else yield 2 ] + let v5 = [ if true then yield 1 ] + let a3 = [| (if true then 1 else 2) |] + let a4 = [| if true then yield 1 else yield 2 |] + let a5 = [| if true then yield 1 |] + let s2 = seq { if true then () else () } + let s6 = seq { if true then () } + let s4 = seq { if true then yield 1 else yield 2 } + let s5 = seq { if true then yield 1 } + + +module BadCurriedExtensionMember = + type C() = + member x.P = 1 + + module M1 = + type C with + member x.M1 a b = a + b + member x.M2 (a,b) c = a + b + c + + module M2 = + type C with + member x.M1 a b = a + b + member x.M2 (a,b) c = a + b + c + + open M1 + open M2 + + let c = C() + + // negative test - error expected here + let x1 : int = c.M1 3 4 + // negative test - error expected here + let x2 : int -> int = c.M1 3 + // negative test - error expected here + let x3 : int -> int -> int = c.M1 + + // negative test - error expected here + let y1 : int = c.M2 (3,4) 4 + // negative test - error expected here + let y2 : int -> int = c.M2 (3,4) + // negative test - error expected here + let y3 : int * int -> int -> int = c.M2 + +type C() = + member x.M(abc:int,def:string) = abc + def.Length + +// Check that the error for a named argument/setter that does not exist is located in a good place +let _ = C().M(qez=3) + +module ListPositive2 = + // In this example, implicit yield is enabled becaue there is no explicit 'yield' + let v3 = + [ if true then 1 else 2 ] + + // In this example, implicit yield is enabled because there is no explicit 'yield'. + // When using implicit yield, statements are detected via a type-directed rule which tries + // checks the statement without an expected type and then checks if the type of the resulting + // expression has type 'unit'. + let v3a = + [ printfn "hello" + if true then 1 else 2 // implicit yield enabled + ] + + // In this example, implicit yield is enabled even though there is an explicit 'yield!' + // This is because using 'yield!' is the only way to yield anything + let v3b = + [ printfn "hello" + if true then 1 else 2 + yield! [] ] + + // This example checks subsumption is permitted when using implicit yield + let v3c : obj list = + [ printfn "hello" + if true then 1 else obj() ] + + // Another check that implicit yield is enabled , even though there is a `yield!` + let v3d = + [ if true then 1 else 2 + yield! [] ] + + // Another check that implicit yield is enabled , even though there is a `yield!` + let v3e = + [ yield! [] + if true then 1 else 2 + ] + + // Another check that implicit yield is enabled + let v3f = + [ if true then + printfn "hello" + 1 + else + 2 ] + + // Another check that implicit yield is enabled + let v3g = + [ if true then + 1 + else + printfn "hello" + 2 ] + + // Another check that implicit yield is enabled + let v3h = + [ for i in 1 .. 10 do + 10 + printfn "hello" ] + + // Another check that implicit yield is enabled + let v5 = + [ if true then 1 ] + + // Another check that implicit yield is enabled + let v5a = + [ printfn "hello"; + if true then 1 ] + + // Another check that implicit yield is enabled + let v5b = + [ if true then + printfn "hello" + 1 + ] + +module ArrayPositive2 = + let a3 = + [| (if true then 1 else 2) |] // simple single element sequence + + let a5 = + [| if true then 1 |] + + let l10 = + [ printfn "hello"; yield 1; yield 2 ] // expect ok - the printfn has type unit and is not interpreted as a yield + + // simple case of explicit yield + let l12 : int list = + [ printfn "hello" + if true then yield 1 else yield 2 ] + + // check subsumption is allowed when using explicit yield + let l13 : obj list = + [ printfn "hello" + if true then yield 1 else yield 2 ] + + // check subsumption is allowed when using explicit yield + let l14 : obj list = + [ printfn "hello" + if true then yield 1 ] + +module SeqPositive2 = + let s2 = + seq { if true then () else () } + + let s6 = + seq { if true then () } + + let s4 = + seq { if true then 1 else 2 } + + let s6 = + seq { if true then 1 } + + let s7 = + seq { match 1 with 1 -> 4 | 2 -> 5 | 3 -> 6 | _ -> () } + +module BuilderPositive2 = + type L<'T> = { Make: (unit -> 'T list) } + let L f = { Make = f } + + type ListBuilder() = + member __.Combine(x1: L<'T>, x2: L<'T>) = L(fun () -> x1.Make() @ x2.Make()) + member __.Delay(f: unit -> L<'T>) = L(fun () -> f().Make()) + member __.Zero() = L(fun () -> []) + member __.Yield(a: 'T) = L(fun () -> [a]) + member __.YieldFrom(x: L<'T>) = x + + let list = ListBuilder() + let empty<'T> : L<'T> = list.Zero() + + let v3 = + list { if true then 1 else 2 } // implicit yield enabled + + let v3y = + list { if true then yield 1 else yield 2 } // equivalent explicit yield + + let v3a = + list { + printfn "hello" + if true then 1 else 2 // implicit yield enabled + } + + let v3ay = + list { + printfn "hello" + if true then yield 1 else yield 2 // equivalent explicit yield + } + + let v3b = + list { + printfn "hello" + if true then 1 else 2 // implicit yield, even though there is a `yield!` + yield! empty + } + + let v3bc = + list { + printfn "hello" + if true then yield 1 else yield 2 // equivalent explicit yield + yield! empty + } + + + + + + + + + + + + + + let v3d = + list { + if true then 1 else 2 // implicit yield enabled , even though there is a `yield!` + yield! empty + } + + let v3dy = + list { + if true then yield 1 else yield 2 // equivalent explicit yield + yield! empty + } + + let v3e = + list { + yield! empty + if true then 1 else 2 // implicit yield enabled , even though there is a `yield!` + } + + let v3f = + list { + if true then + printfn "hello" + 1 + else 2 + } + + let v3g = + list { + if true then + 1 + else + printfn "hello" + 2 + } + + let v5 = + list { + if true then 1 + } + + let v5a = + list { + printfn "hello"; + if true then 1 + } + + let v5b = + list { + if true then + printfn "hello" + 1 + } + +module ListNegative2 = + let v4 = [ if true then 1 else yield 2 ] // expect warning about "1" being ignored. There is a 'yield' so statements are statements. + let l11 = [ 4; yield 1; yield 2 ] // expect warning about "1" being ignored. There is a 'yield' so statements are statements. + let l9 = [ printfn "hello"; 1; 2 ] // Note, this is interpreted as a "SimpleSemicolonSequence", so we get "All elements of a list must be implicitly convertible to the type of the first element, which here is 'unit'. This element..." + let v3a : unit list = + [ printfn "hello" + if true then 1 else 2 ] + +module ArrayNegative2 = + let a4 = [| if true then 1 else yield 2 |] // expect warning about "1" being ignored. There is a 'yield' so statements are statements. + let a4 = [| (if true then 1) |] + +module SeqNegative2 = + let s5 = seq { if true then 1 else yield 2 } // expect warning about "1" being ignored. There is a 'yield' so statements are statements. + let s8 = seq { match 1 with 1 -> 4 | 2 -> 5 | 3 -> yield 6 | _ -> () } // expect warning about "4" being ignored. There is a 'yield' so statements are statements. + +module BuilderNegative2 = + type L<'T> = { Make: (unit -> 'T list) } + let L f = { Make = f } + + type ListBuilder() = + member __.Combine(x1: L<'T>, x2: L<'T>) = L(fun () -> x1.Make() @ x2.Make()) + member __.Delay(f: unit -> L<'T>) = L(fun () -> f().Make()) + member __.Zero() = L(fun () -> []) + member __.Yield(a: 'T) = L(fun () -> [a]) + member __.YieldFrom(x: L<'T>) = x + + let list = ListBuilder() + + let v3c : L = + list { + printfn "hello" + if true then 1 else obj() + } + + let v3c : L = + list { + printfn "hello" + if true then yield 1 else obj() + } + diff --git a/tests/fsharp/typecheck/sigs/neg80.vsbsl b/tests/fsharp/typecheck/sigs/neg80.vsbsl index d8bb6d1a0bb..26c5bcafa24 100644 --- a/tests/fsharp/typecheck/sigs/neg80.vsbsl +++ b/tests/fsharp/typecheck/sigs/neg80.vsbsl @@ -3,6 +3,6 @@ neg80.fsx(79,5,79,6): parse error FS0010: Unexpected symbol '|' in pattern match neg80.fsx(79,5,79,6): parse error FS0010: Unexpected symbol '|' in pattern matching -neg80.fsx(79,6,79,6): typecheck error FS0001: All branches of a pattern match expression must return values of the same type as the first branch, which here is 'string'. This branch returns a value of type 'unit'. +neg80.fsx(79,6,79,6): typecheck error FS0001: All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is 'string'. This branch returns a value of type 'unit'. neg80.fsx(76,11,76,13): typecheck error FS0025: Incomplete pattern matches on this expression. For example, the value 'Horizontal (_, _)' may indicate a case not covered by the pattern(s). diff --git a/tests/fsharp/typecheck/sigs/version47/neg24.bsl b/tests/fsharp/typecheck/sigs/version47/neg24.bsl index f276c01968b..e2471fb7b86 100644 --- a/tests/fsharp/typecheck/sigs/version47/neg24.bsl +++ b/tests/fsharp/typecheck/sigs/version47/neg24.bsl @@ -17,9 +17,9 @@ neg24.fs(300,29,300,30): typecheck error FS0020: The result of this expression h neg24.fs(301,17,301,18): typecheck error FS0020: The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'. -neg24.fs(302,33,302,34): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'unit'. This element has type 'int'. +neg24.fs(302,33,302,34): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'unit'. This element has type 'int'. -neg24.fs(302,36,302,37): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'unit'. This element has type 'int'. +neg24.fs(302,36,302,37): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'unit'. This element has type 'int'. neg24.fs(304,11,305,32): typecheck error FS0193: Type constraint mismatch. The type 'int' diff --git a/tests/fsharp/typecheck/sigs/version47/neg24.fs b/tests/fsharp/typecheck/sigs/version47/neg24.fs index 6e1e072cf1a..38cb01cf2d2 100644 --- a/tests/fsharp/typecheck/sigs/version47/neg24.fs +++ b/tests/fsharp/typecheck/sigs/version47/neg24.fs @@ -299,7 +299,7 @@ module BuilderPositive2 = module ListNegative2 = let v4 = [ if true then 1 else yield 2 ] // expect warning about "1" being ignored. There is a 'yield' so statements are statements. let l11 = [ 4; yield 1; yield 2 ] // expect warning about "1" being ignored. There is a 'yield' so statements are statements. - let l9 = [ printfn "hello"; 1; 2 ] // Note, this is interpreted as a "SimpleSemicolonSequence", so we get "All elements of a list must be of the same type as the first element, which here is 'unit'. This element..." + let l9 = [ printfn "hello"; 1; 2 ] // Note, this is interpreted as a "SimpleSemicolonSequence", so we get "All elements of a list must be implicitly convertible to the type of the first element, which here is 'unit'. This element..." let v3a : unit list = [ printfn "hello" if true then 1 else 2 ] diff --git a/tests/fsharp/typecheck/sigs/version50/neg20.bsl b/tests/fsharp/typecheck/sigs/version50/neg20.bsl new file mode 100644 index 00000000000..88d816d6644 --- /dev/null +++ b/tests/fsharp/typecheck/sigs/version50/neg20.bsl @@ -0,0 +1,417 @@ + +neg20.fs(30,28,30,31): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(31,32,31,35): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(32,28,32,31): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(32,32,32,35): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(34,24,34,27): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +neg20.fs(35,24,35,27): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(43,15,43,18): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(44,19,44,22): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(45,15,45,18): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(45,19,45,22): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(47,11,47,14): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +neg20.fs(48,11,48,14): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(52,24,52,31): typecheck error FS0001: This expression was expected to have type + 'A' +but here has type + 'B' + +neg20.fs(53,38,53,39): typecheck error FS0001: This expression was expected to have type + 'System.ValueType' +but here has type + 'int' + +neg20.fs(60,26,60,33): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'B'. This element has type 'A'. + +neg20.fs(61,27,61,35): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'B1'. This element has type 'B2'. + +neg20.fs(62,26,62,33): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'C'. This element has type 'B'. + +neg20.fs(66,25,66,32): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'A'. This element has type 'B'. + +neg20.fs(67,27,67,34): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'B'. This element has type 'C'. + +neg20.fs(70,31,70,38): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'B'. This element has type 'C'. + +neg20.fs(71,34,71,42): typecheck error FS0001: Type mismatch. Expecting a + 'A list' +but given a + 'B list' +The type 'A' does not match the type 'B' + +neg20.fs(75,30,75,37): typecheck error FS0001: This expression was expected to have type + 'B' +but here has type + 'C' + +neg20.fs(76,34,76,43): typecheck error FS0001: Type mismatch. Expecting a + 'A list' +but given a + 'B list' +The type 'A' does not match the type 'B' + +neg20.fs(80,23,80,39): typecheck error FS0193: Type constraint mismatch. The type + 'C list' +is not compatible with type + 'seq' + + +neg20.fs(81,34,81,43): typecheck error FS0001: Type mismatch. Expecting a + 'A list' +but given a + 'B list' +The type 'A' does not match the type 'B' + +neg20.fs(83,47,83,54): typecheck error FS0001: All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is 'B'. This branch returns a value of type 'C'. + +neg20.fs(87,54,87,61): typecheck error FS0001: All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is 'B'. This branch returns a value of type 'C'. + +neg20.fs(92,19,92,26): typecheck error FS0001: This expression was expected to have type + 'A' +but here has type + 'B' + +neg20.fs(96,26,96,33): typecheck error FS0001: This expression was expected to have type + 'B' +but here has type + 'A' + +neg20.fs(97,26,97,33): typecheck error FS0001: This expression was expected to have type + 'A' +but here has type + 'B' + +neg20.fs(99,26,99,33): typecheck error FS0001: All elements of a list must be implicitly convertible to the type of the first element, which here is 'B'. This element has type 'A'. + +neg20.fs(108,12,108,16): typecheck error FS0001: Type mismatch. Expecting a + 'B * B -> 'a' +but given a + 'A * A -> Data' +The type 'B' does not match the type 'A' + +neg20.fs(109,12,109,16): typecheck error FS0001: Type mismatch. Expecting a + 'A * B -> 'a' +but given a + 'A * A -> Data' +The type 'B' does not match the type 'A' + +neg20.fs(110,12,110,16): typecheck error FS0001: Type mismatch. Expecting a + 'B * A -> 'a' +but given a + 'A * A -> Data' +The type 'B' does not match the type 'A' + +neg20.fs(128,19,128,22): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(129,19,129,22): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +neg20.fs(131,5,131,24): typecheck error FS0041: No overloads match for method 'OM3'. + +Known types of arguments: string * obj + +Available overloads: + - static member C.OM3 : x:'b * y:'b -> int // Argument 'y' doesn't match + - static member C.OM3 : x:'b * y:int -> int // Argument 'y' doesn't match + +neg20.fs(152,13,152,23): typecheck error FS0033: The type 'Test.BadNumberOfGenericParameters.C<_>' expects 1 type argument(s) but is given 2 + +neg20.fs(153,13,153,23): typecheck error FS0033: The type 'Test.BadNumberOfGenericParameters.C<_>' expects 1 type argument(s) but is given 2 + +neg20.fs(154,13,154,25): typecheck error FS0502: The member or object constructor 'SM1' takes 0 type argument(s) but is here given 1. The required signature is 'static member C.SM1 : unit -> int'. + +neg20.fs(155,13,155,26): typecheck error FS0502: The member or object constructor 'SM2' takes 0 type argument(s) but is here given 1. The required signature is 'static member C.SM2 : y:int -> int'. + +neg20.fs(156,13,156,28): typecheck error FS0502: The member or object constructor 'SM3' takes 0 type argument(s) but is here given 1. The required signature is 'static member C.SM3 : y:int * z:int -> int'. + +neg20.fs(157,28,157,29): typecheck error FS0495: The member or object constructor 'SM3' has no argument or settable return property 'x'. The required signature is static member C.SM3 : y:int * z:int -> int. + +neg20.fs(158,13,158,36): typecheck error FS0502: The member or object constructor 'SM4' takes 1 type argument(s) but is here given 2. The required signature is 'static member C.SM4 : y:'a * z:'b -> int'. + +neg20.fs(159,13,159,32): typecheck error FS0502: The member or object constructor 'SM5' takes 2 type argument(s) but is here given 1. The required signature is 'static member C.SM5 : y:'a * z:'b -> int'. + +neg20.fs(162,13,162,24): typecheck error FS0502: The member or object constructor 'M1' takes 0 type argument(s) but is here given 1. The required signature is 'member C.M1 : unit -> int'. + +neg20.fs(163,13,163,25): typecheck error FS0502: The member or object constructor 'M2' takes 0 type argument(s) but is here given 1. The required signature is 'member C.M2 : y:int -> int'. + +neg20.fs(164,13,164,27): typecheck error FS0502: The member or object constructor 'M3' takes 0 type argument(s) but is here given 1. The required signature is 'member C.M3 : y:int * z:int -> int'. + +neg20.fs(165,27,165,28): typecheck error FS0495: The member or object constructor 'M3' has no argument or settable return property 'x'. The required signature is member C.M3 : y:int * z:int -> int. + +neg20.fs(166,13,166,35): typecheck error FS0502: The member or object constructor 'M4' takes 1 type argument(s) but is here given 2. The required signature is 'member C.M4 : y:'a * z:'b -> int'. + +neg20.fs(167,13,167,31): typecheck error FS0502: The member or object constructor 'M5' takes 2 type argument(s) but is here given 1. The required signature is 'member C.M5 : y:'a * z:'b -> int'. + +neg20.fs(182,14,182,31): typecheck error FS0041: No overloads match for method 'M'. + +Known types of arguments: string * obj + +Available overloads: + - static member C2.M : fmt:string * [] args:int [] -> string // Argument 'args' doesn't match + - static member C2.M : fmt:string * [] args:int [] -> string // Argument at index 1 doesn't match + +neg20.fs(183,29,183,34): typecheck error FS0001: This expression was expected to have type + 'int' +but here has type + 'obj' + +neg20.fs(183,29,183,34): typecheck error FS0001: This expression was expected to have type + 'int' +but here has type + 'obj' + +neg20.fs(183,35,183,40): typecheck error FS0001: This expression was expected to have type + 'int' +but here has type + 'obj' + +neg20.fs(183,35,183,40): typecheck error FS0001: This expression was expected to have type + 'int' +but here has type + 'obj' + +neg20.fs(183,14,183,41): typecheck error FS0001: This expression was expected to have type + 'unit' +but here has type + 'string' + +neg20.fs(184,28,184,33): typecheck error FS0001: This expression was expected to have type + 'int' +but here has type + 'obj' + +neg20.fs(184,28,184,33): typecheck error FS0001: This expression was expected to have type + 'int' +but here has type + 'obj' + +neg20.fs(184,34,184,39): typecheck error FS0001: This expression was expected to have type + 'int' +but here has type + 'obj' + +neg20.fs(184,34,184,39): typecheck error FS0001: This expression was expected to have type + 'int' +but here has type + 'obj' + +neg20.fs(188,14,188,31): typecheck error FS0041: No overloads match for method 'M'. + +Known types of arguments: string * obj + +Available overloads: + - static member C3.M : fmt:string * [] args:string [] -> string // Argument 'args' doesn't match + - static member C3.M : fmt:string * [] args:string [] -> string // Argument at index 1 doesn't match + +neg20.fs(189,29,189,34): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(189,29,189,34): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(189,35,189,40): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(189,35,189,40): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(189,14,189,41): typecheck error FS0001: This expression was expected to have type + 'unit' +but here has type + 'string' + +neg20.fs(190,28,190,33): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(190,28,190,33): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(190,34,190,39): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(190,34,190,39): typecheck error FS0001: This expression was expected to have type + 'string' +but here has type + 'obj' + +neg20.fs(195,5,195,10): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(198,5,198,11): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(201,3,202,9): typecheck error FS0825: The 'DefaultValue' attribute may only be used on 'val' declarations + +neg20.fs(204,5,204,14): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(207,5,207,11): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(210,5,210,12): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(213,5,213,33): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(216,5,216,12): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(219,5,219,15): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(222,5,222,24): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(225,5,225,22): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(228,5,228,23): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(231,5,231,21): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(234,5,234,34): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(237,5,237,34): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(240,5,240,23): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(243,5,243,23): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(249,9,249,27): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(255,5,255,21): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(258,5,258,31): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(261,5,261,17): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(265,5,265,24): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(268,5,268,27): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(271,5,271,13): typecheck error FS0842: This attribute is not valid for use on this language element + +neg20.fs(278,14,278,95): typecheck error FS0507: No accessible member or object constructor named 'ProcessStartInfo' takes 0 arguments. Note the call to this member also provides 2 named arguments. + +neg20.fs(280,14,280,94): typecheck error FS0508: No accessible member or object constructor named 'ProcessStartInfo' takes 0 arguments. The named argument 'Argument' doesn't correspond to any argument or settable return property for any overload. + +neg20.fs(285,12,285,13): typecheck error FS0038: 'x' is bound twice in this pattern + +neg20.fs(286,14,286,15): typecheck error FS0038: 'x' is bound twice in this pattern + +neg20.fs(288,17,288,18): typecheck error FS0038: 'x' is bound twice in this pattern + +neg20.fs(294,5,294,36): typecheck error FS0840: Unrecognized attribute target. Valid attribute targets are 'assembly', 'module', 'type', 'method', 'property', 'return', 'param', 'field', 'event', 'constructor'. + +neg20.fs(301,8,301,16): typecheck error FS3132: This type definition may not have the 'CLIMutable' attribute. Only record types may have this attribute. + +neg20.fs(304,8,304,16): typecheck error FS3132: This type definition may not have the 'CLIMutable' attribute. Only record types may have this attribute. + +neg20.fs(307,8,307,20): typecheck error FS3132: This type definition may not have the 'CLIMutable' attribute. Only record types may have this attribute. + +neg20.fs(310,8,310,17): typecheck error FS3132: This type definition may not have the 'CLIMutable' attribute. Only record types may have this attribute. + +neg20.fs(313,8,313,15): typecheck error FS3132: This type definition may not have the 'CLIMutable' attribute. Only record types may have this attribute. + +neg20.fs(316,8,316,19): typecheck error FS3132: This type definition may not have the 'CLIMutable' attribute. Only record types may have this attribute. + +neg20.fs(319,8,319,17): typecheck error FS3132: This type definition may not have the 'CLIMutable' attribute. Only record types may have this attribute. + +neg20.fs(322,8,322,18): typecheck error FS3132: This type definition may not have the 'CLIMutable' attribute. Only record types may have this attribute. + +neg20.fs(335,11,335,24): typecheck error FS0041: A unique overload for method 'String' could not be determined based on type information prior to this program point. A type annotation may be needed. + +Known type of argument: 'a0 + +Candidates: + - System.String(value: char []) : System.String + - System.String(value: nativeptr) : System.String + - System.String(value: nativeptr) : System.String + +neg20.fs(336,11,336,22): typecheck error FS0041: A unique overload for method 'Guid' could not be determined based on type information prior to this program point. A type annotation may be needed. + +Known type of argument: 'a0 + +Candidates: + - System.Guid(b: byte []) : System.Guid + - System.Guid(g: string) : System.Guid + +neg20.fs(355,19,355,38): typecheck error FS1124: Multiple types exist called 'OverloadedClassName', taking different numbers of generic parameters. Provide a type instantiation to disambiguate the type resolution, e.g. 'OverloadedClassName<_>'. + +neg20.fs(356,22,356,41): typecheck error FS1124: Multiple types exist called 'OverloadedClassName', taking different numbers of generic parameters. Provide a type instantiation to disambiguate the type resolution, e.g. 'OverloadedClassName<_>'. + +neg20.fs(370,19,370,38): typecheck error FS1133: No constructors are available for the type 'OverloadedClassName<'a,'b>' + +neg20.fs(371,19,371,38): typecheck error FS1124: Multiple types exist called 'OverloadedClassName', taking different numbers of generic parameters. Provide a type instantiation to disambiguate the type resolution, e.g. 'OverloadedClassName<_>'. + +neg20.fs(372,22,372,41): typecheck error FS1133: No constructors are available for the type 'OverloadedClassName<'a,'b>' + +neg20.fs(373,22,373,41): typecheck error FS1124: Multiple types exist called 'OverloadedClassName', taking different numbers of generic parameters. Provide a type instantiation to disambiguate the type resolution, e.g. 'OverloadedClassName<_>'. + +neg20.fs(382,19,382,40): typecheck error FS1124: Multiple types exist called 'OverloadedClassName', taking different numbers of generic parameters. Provide a type instantiation to disambiguate the type resolution, e.g. 'OverloadedClassName<_>'. + +neg20.fs(383,39,383,41): typecheck error FS0039: The type 'OverloadedClassName' does not define the field, constructor or member 'S2'. + +neg20.fs(428,19,428,38): typecheck error FS1133: No constructors are available for the type 'OverloadedClassName<'a,'b>' + +neg20.fs(430,22,430,41): typecheck error FS1133: No constructors are available for the type 'OverloadedClassName<'a,'b>' + +neg20.fs(444,39,444,41): typecheck error FS0039: The type 'OverloadedClassName' does not define the field, constructor or member 'S2'. diff --git a/tests/fsharp/typecheck/sigs/version50/neg20.fs b/tests/fsharp/typecheck/sigs/version50/neg20.fs new file mode 100644 index 00000000000..1574d4d3340 --- /dev/null +++ b/tests/fsharp/typecheck/sigs/version50/neg20.fs @@ -0,0 +1,445 @@ +module Test + +type A() = + member x.P = 1 + +type B() = + inherit A() + member x.P = 1 + +type B1() = + inherit A() + member x.P = 1 + +type B2() = + inherit A() + member x.P = 1 + + +type C() = + inherit B() + member x.P = 1 + +module BiGenericStaticMemberTests = + type StaticClass1() = + static member M<'b>(c:'b, d:'b) = 1 + + let obj = new obj() + let str = "" + + StaticClass1.M(obj,str) + StaticClass1.M(str,obj) + StaticClass1.M(obj,obj) + + StaticClass1.M(obj,str) // obj :> 'b --> obj = 'b + StaticClass1.M(str,obj) // string :> 'b --> string = 'b + +module BiGenericFunctionTests = + let M<'b>(c:'b, d:'b) = 1 + + let obj = new obj() + let str = "" + + M(obj,str) + M(str,obj) + M(obj,obj) + + M(obj,str) // obj :> 'b --> obj = 'b + M(str,obj) // string :> 'b --> string = 'b + + +module NoSubsumptionOnApplication = + (fun (x:A) -> 1) (new B()) // now permitted + (fun (x:System.ValueType) -> 1) 1 // coercion on application! + + +module NoSubsumptionForLists = + type StaticClass2() = + static member DisplayControls(controls: A list) = () + + let v21 = [ new B(); new A() ] + let v22 = [ new B1(); new B2() ] + let v2b = [ new C(); new B() ] + let v2c : A list = [ new B(); new C() ] + StaticClass2.DisplayControls [ new B1(); new B2() ] + + let v2 = [ new A(); new B() ] + let v2b' = [ new B(); new C() ] + let v2c' : A list = [ (new B() :> A); new C() ] + + let controls = [ new B(); new C() ] + StaticClass2.DisplayControls controls // bang + + // Q: how about on sequence expressions? + let controls2 = [ yield (new B()) + yield (new C()) ] + StaticClass2.DisplayControls controls2 + + // Q: how about on sequence expressions? + let controls3 = [ yield! [new B()] + yield! [new C()] ] + StaticClass2.DisplayControls controls3 // bang + + let controls4 = if true then new B() else new C() + StaticClass2.DisplayControls [controls4] // allowed + + // Q: how about on matches? allowed + let controls5 = match 1 with 1 -> new B() | _ -> new C() + StaticClass2.DisplayControls [controls5] // allowed + + + // Q. subsumption on 'let v = expr'? Allowed + let x76 : A = new B() + +module NoSubsumptionForLists2 = + + let d1 = new B() :: new A() :: [] + let d2 = new A() :: new B() :: [] + + let v2a = [ new B(); new A() ] // would not work! + // cf. let v2b = [ (new B() :> A); new A() ] + + type Data = Data of A * A + let data (x,y) = Data (x,y) + let pAA = (new A(),new A()) + let pBB = (new B(),new B()) + let pAB = (new A(),new B()) + let pBA = (new B(),new A()) + pBB |> Data // not permitted (questionable) + pAB |> Data // not permitted (questionable) + pBA |> Data // not permitted (questionable) + pBB |> data // permitted + pAB |> data // permitted + pBA |> data // permitted + +module BiGenericMethodsInGenericClassTests = + type C<'a>() = + static member M(x:'a) = 1 + static member M2<'b>(x:'b) = 1 + static member M3<'b>(x:'b,y:'b) = 1 + + static member OM3<'b>(x:'b,y:'b) = 1 + + static member OM3<'b>(x:'b,y:int) = 1 + + let obj = new obj() + let str = "" + + C.M3("a",obj) // this is not permitted since 'b is inferred to be "string". Fair enough + C.M3(obj,"a") // now permitted + + C.OM3("a",obj) // this is not permitted since 'b is inferred to be "string". Fair enough + + + + +module BadNumberOfGenericParameters = + + type C<'a>() = + member x.P = 1 + member x.M1() = 2 + member x.M2(y:int) = 2 + member x.M3(y:int,z:int) = 2 + member x.M4<'b>(y:'a,z:'b) = 2 + member x.M5<'b,'c>(y:'a,z:'b) = 2 + + static member SP = 1 + static member SM1() = 2 + static member SM2(y:int) = 2 + static member SM3(y:int,z:int) = 2 + static member SM4<'b>(y:'a,z:'b) = 2 + static member SM5<'b,'c>(y:'a,z:'b) = 2 + let _ = C.SP + let _ = C.M1 + let _ = C.SM1() // expect error here + let _ = C.SM2(3) // expect error here + let _ = C.SM3(3,4) // expect error here + let _ = C.SM3(y=3,x=4) // expect error here + let _ = C.SM4(y=3,z=4) // expect error here + let _ = C.SM5(y=3,z=4) // expect error here + + let c = C() + let _ = c.M1() // expect error here + let _ = c.M2(3) // expect error here + let _ = c.M3(3,4) // expect error here + let _ = c.M3(y=3,x=4) // expect error here + let _ = c.M4(y=3,z=4) // expect error here + let _ = c.M5(y=3,z=4) // expect error here + + module PositiveTests = + let _ = C.SM4(y=3,z=4) // expect NO NO NO NO NO error here + let _ = C.SM4(y=3,z=4) // expect NO NO NO NO NO error here + let _ = C.SM5(y=3,z=4) // expect NO NO NO NO NO error here + let _ = c.M4(y=3,z=4) // expect NO NO NO NO NO error here + let _ = c.M4(y=3,z=4) // expect NO NO NO NO NO error here + let _ = c.M5(y=3,z=4) // expect NO NO NO NO NO error here + + +module ParamArgs = begin + type C2() = class + static member M( fmt:string, [] args : int[]) = System.String.Format(fmt,args) + end + let () = C2.M("{0}",box 1) // expect error + let () = C2.M("{0},{1}",box 1,box 2) // expect error + let _ = C2.M("{0},{1}",box 1,box 2) // expect error + type C3() = class + static member M( fmt:string, [] args : string[]) = System.String.Format(fmt,args) + end + let () = C3.M("{0}",box 1) // expect error + let () = C3.M("{0},{1}",box 1,box 2) // expect error + let _ = C3.M("{0},{1}",box 1,box 2) // expect error +end + +module BadAttribute = begin + + [] + let T1 = 1 + + [] + let T2 = 1 + + [] + let T3 = 1 + + [] + let T4 = 1 + + [] + let T5 = 1 + + [] + let T6 = 1 + + [] + let T7 = 1 + + [] + type C1() = class end + + [] + type C2() = class end + + [] + let T8 = 1 + + [] + let T9 = 1 + + [] + let T10 = 1 + + [] + let T11 = 1 + + [] + type C3() = class end + + [] + module M = begin end + + [] + module M2 = begin end + + [] + type C4() = class end + + + type C5 = + class + [] val x : int + end + + + type C6() = class end + + [] + let T12 = 1 + + [] + let T13 = 1 + + [] + type C7() = class end + + + [] + type C8() = class end + + [] + let T14 = 1 + + [] + let T15 = 1 + +end + +module BadArgName = begin + + let psi1 = new System.Diagnostics.ProcessStartInfo(FileName = "test", arguments = "testarg") + + let psi2 = new System.Diagnostics.ProcessStartInfo(FileName = "test", Argument = "testarg") +end + +module DuplicateArgNames = begin + + let f1 x x = () + let f2 x _ x = () + type C() = + member x.M(x:int) = x + x +end + + +module BogusAttributeTarget = begin + + [] + let x = 5 +end + +module BogusUseOfCLIMutable = begin + + [] + type BadClass() = member x.P = 1 + + [] + type BadUnion = A | B + + [] + type BadInterface = interface end + + [] + type BadClass2 = class end + + [] + type BadEnum = | A = 1 | B = 2 + + [] + type BadDelegate = delegate of int * int -> int + + [] + type BadStruct = struct val x : int end + + [] + type BadStruct2(x:int) = struct member v.X = x end + + [] + type Good1 = { x : int; y : int } + let good1 = { x = 1; y = 2 } + + [] + type Good2 = { x : int } + let good2 = { x = 1 } + +end + + +let ss1 = System.String +let ss2 = System.Guid + +type ClassWithOneConstructor(x:int) = member x.P = 1 + +let ss3 = ClassWithOneConstructor + + +module OverloadedTypeNamesBothHaveConstructors = + type OverloadedClassName<'T>(x:int) = + new (y:string) = OverloadedClassName<'T>(1) + member __.P = x + static member S() = 3 + + + type OverloadedClassName<'T1,'T2>(x:int) = + new (y:string) = OverloadedClassName<'T1,'T2>(1) + member __.P = x + static member S() = 3 + + let t3 = 3 |> OverloadedClassName // expected error - multiple types exist + let t3s = "3" |> OverloadedClassName // expected error - multiple types exist + + +module OverloadedTypeNamesSomeConstructors = + type OverloadedClassName<'T>(x:int) = + new (y:string) = OverloadedClassName<'T>(1) + member __.P = x + static member S() = 3 + + + type OverloadedClassName<'T1,'T2> = + member __.P = 1 + static member S() = 3 + + let t2 = 3 |> OverloadedClassName // CHANGE IN ERROR MESSAGE IN F# 4.x: Was "Invalid use of a type name", now "No constructors are available for the type 'OverloadedClassName<'a,'b>'" + let t3 = 3 |> OverloadedClassName // expected error - multiple types exist + let t2s = "3" |> OverloadedClassName // CHANGE IN ERROR MESSAGE IN F# 4.x: Was "Invalid use of a type name", now "No constructors are available for the type 'OverloadedClassName<'a,'b>'" + let t3s = "3" |> OverloadedClassName // expected error - multiple types exist + +module OverloadedTypeNamesNoConstructors = + type OverloadedClassName<'T> = + static member S(x:int) = 3 + + type OverloadedClassName<'T1,'T2> = + static member S(x:int) = 3 + + let t3 = 3 |> OverloadedClassName.S // expected error - multiple types exist + let t4 = 3 |> OverloadedClassName.S2 // expected error - The field, constructor or member 'S2' is not defined + + + + + + +module OverloadedTypeNamesIncludingNonGenericTypeBothHaveConstructors = + + type OverloadedClassName(x:int) = + new (y:string) = OverloadedClassName(1) + member __.P = x + static member S() = 3 + + type OverloadedClassName<'T>(x:int) = + new (y:string) = OverloadedClassName<'T>(1) + member __.P = x + static member S() = 3 + + + type OverloadedClassName<'T1,'T2>(x:int) = + new (y:string) = OverloadedClassName<'T1,'T2>(1) + member __.P = x + static member S() = 3 + + let t3 = 3 |> OverloadedClassName // expected error - multiple types exist + let t3s = "3" |> OverloadedClassName // expected error - multiple types exist + + +module OverloadedTypeNamesIncludingNonGenericTypeSomeConstructors = + type OverloadedClassName(x:int) = + new (y:string) = OverloadedClassName(1) + member __.P = x + static member S() = 3 + + type OverloadedClassName<'T>(x:int) = + new (y:string) = OverloadedClassName<'T>(1) + member __.P = x + static member S() = 3 + + + type OverloadedClassName<'T1,'T2> = + member __.P = 1 + static member S() = 3 + + let t2 = 3 |> OverloadedClassName // CHANGE IN ERROR MESSAGE IN F# 4.x: Was "Invalid use of a type name", now "No constructors are available for the type 'OverloadedClassName<'a,'b>'" + let t3 = 3 |> OverloadedClassName // NO ERROR EXPECTED + let t2s = "3" |> OverloadedClassName // CHANGE IN ERROR MESSAGE IN F# 4.x: Was "Invalid use of a type name", now "No constructors are available for the type 'OverloadedClassName<'a,'b>'" + let t3s = "3" |> OverloadedClassName // expected error - multiple types exist + +module OverloadedTypeNamesIncludingNonGenericTypeNoConstructors = + type OverloadedClassName = + static member S(x:int) = 3 + + type OverloadedClassName<'T> = + static member S(x:int) = 3 + + type OverloadedClassName<'T1,'T2> = + static member S(x:int) = 3 + + let t3 = 3 |> OverloadedClassName.S // NO ERROR EXPECTED + let t4 = 3 |> OverloadedClassName.S2 // expected error - The field, constructor or member 'S2' is not defined + diff --git a/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/E_rigidtypeannotation02.fs b/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/E_rigidtypeannotation02.fs deleted file mode 100644 index 4de91d2b113..00000000000 --- a/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/E_rigidtypeannotation02.fs +++ /dev/null @@ -1,11 +0,0 @@ -// #Regression #Conformance #TypeRelatedExpressions #TypeAnnotations -// Regression test for FSHARP1.0:2346 -//This expression was expected to have type. 'obj' .but here has type. 'int' -//This expression was expected to have type. 'obj' .but here has type. 'string' -//This expression was expected to have type. 'seq<'a>' .but here has type. ''b list' - -(1 : obj) -("Hello" : obj) -([1.0;2.0;3.0] : seq<_>).GetEnumerator() - - diff --git a/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/E_rigidtypeannotation02b.fs b/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/E_rigidtypeannotation02b.fs deleted file mode 100644 index 49b034a71b6..00000000000 --- a/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/E_rigidtypeannotation02b.fs +++ /dev/null @@ -1,8 +0,0 @@ -// #Regression #Conformance #TypeRelatedExpressions #TypeAnnotations -// Regression test for FSHARP1.0:2346 -//This expression was expected to have type. 'obj' .but here has type. 'float' -//This expression was expected to have type. 'seq<'a>' .but here has type. ''b list' - -[] type s -(1.0 : obj) -([1.0;2.0;3.0] : seq<_>).GetEnumerator() diff --git a/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/env.lst b/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/env.lst index 22eeab4a4a6..32ad3087012 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/env.lst +++ b/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/env.lst @@ -15,8 +15,6 @@ SOURCE=E_RigidTypeAnnotation01.fsx SCFLAGS="--test:ErrorRanges --flaterrors" # E_RigidTypeAnnotation01.fsx SOURCE=E_RigidTypeAnnotation02.fsx SCFLAGS="--test:ErrorRanges --flaterrors" # E_RigidTypeAnnotation02.fsx - SOURCE=E_rigidtypeannotation02.fs COMPILE_ONLY=1 SCFLAGS="--test:ErrorRanges --flaterrors" # E_rigidtypeannotation02.fs - SOURCE=E_rigidtypeannotation02b.fs COMPILE_ONLY=1 SCFLAGS="--test:ErrorRanges --flaterrors" # E_rigidtypeannotation02b.fs SOURCE=E_RigidTypeAnnotation03.fs SCFLAGS="--test:ErrorRanges --flaterrors" # E_RigidTypeAnnotation03.fs SOURCE=staticcoercion01.fs COMPILE_ONLY=1 # staticcoercion01.fs diff --git a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/E_NoImplicitDowncast01.fs b/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/E_NoImplicitDowncast01.fs deleted file mode 100644 index dcdb70a86cc..00000000000 --- a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/E_NoImplicitDowncast01.fs +++ /dev/null @@ -1,14 +0,0 @@ -// #Regression #Conformance #TypeInference #TypeConstraints -// Verify no implicit downlcast -//This expression was expected to have type. 'Foo' .but here has type. 'Bar' - -type Foo() = - override this.ToString() = "Foo" - -type Bar() = - inherit Foo() - override this.ToString() = "Bar" - - -let a = new Foo() -let b : Foo = new Bar() // Should fail diff --git a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/env.lst b/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/env.lst index 1033d17c940..09bfdb1fb25 100644 --- a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/env.lst +++ b/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/env.lst @@ -1,5 +1,3 @@ - SOURCE=E_NoImplicitDowncast01.fs SCFLAGS="--test:ErrorRanges --flaterrors" # E_NoImplicitDowncast01.fs - SOURCE=E_TypeFuncDeclaredExplicit01.fs # E_TypeFuncDeclaredExplicit01.fs SOURCE=ValueRestriction01.fs # ValueRestriction01.fs diff --git a/tests/fsharpqa/Source/Diagnostics/async/ReturnBangNonAsync_IfThenElse.fs b/tests/fsharpqa/Source/Diagnostics/async/ReturnBangNonAsync_IfThenElse.fs index 74f2176d4cf..ecc1175241d 100644 --- a/tests/fsharpqa/Source/Diagnostics/async/ReturnBangNonAsync_IfThenElse.fs +++ b/tests/fsharpqa/Source/Diagnostics/async/ReturnBangNonAsync_IfThenElse.fs @@ -1,6 +1,6 @@ // #Regression #Diagnostics #Async // Regression tests for FSHARP1.0:4394 -//All branches of an 'if' expression must return values of the same type as the first branch +//All branches of an 'if' expression must return values implicitly convertible to the type of the first branch async { if true then return () else