From 3bc197cac30df84817778b49543bd92ecc6cc07a Mon Sep 17 00:00:00 2001 From: Don Syme Date: Fri, 15 Jan 2021 15:16:51 +0000 Subject: [PATCH 01/42] merge main --- src/fsharp/CheckDeclarations.fs | 2 +- src/fsharp/CheckExpressions.fs | 427 +++++++++++++++++++------------- src/fsharp/CheckExpressions.fsi | 21 +- 3 files changed, 269 insertions(+), 181 deletions(-) diff --git a/src/fsharp/CheckDeclarations.fs b/src/fsharp/CheckDeclarations.fs index 6d2d38ef198..5733544662d 100644 --- a/src/fsharp/CheckDeclarations.fs +++ b/src/fsharp/CheckDeclarations.fs @@ -521,7 +521,7 @@ module TcRecdUnionAndEnumDeclarations = | SynConst.UInt16s _ | SynConst.UserNum _ -> error(Error(FSComp.SR.tcInvalidEnumerationLiteral(), m)) | _ -> - let v = TcConst cenv fieldTy m env v + let v = TcConst cenv (MustEqual fieldTy) m env v let vis, _ = ComputeAccessAndCompPath env None m None None parent let vis = CombineReprAccess parent vis if id.idText = "value__" then errorR(Error(FSComp.SR.tcNotValidEnumCaseName(), id.idRange)) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index b30ae9cd30c..9a33f3a3092 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -513,6 +513,18 @@ let LocateEnv ccu env enclosingNamespacePath = let env = { env with eNameResEnv = { env.NameEnv with eDisplayEnv = env.DisplayEnv.AddOpenPath (pathOfLid env.ePath) } } env +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 ty: TType + + /// Represents a point where no subsumption/widening is possible + member x.Commit = + match x with + | MustEqual ty -> ty + | MustConvertTo ty -> ty //------------------------------------------------------------------------- // Helpers for unification @@ -743,7 +755,8 @@ 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: OverallTy) m env c = + let overallTy = overallTy.Commit // TODO: opportunities for subsumption and widening here let rec tcMeasure ms = match ms with | SynMeasure.One -> Measure.One @@ -765,7 +778,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 = @@ -4421,7 +4434,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 @@ -4804,7 +4817,7 @@ and TcPat warnOnUpper cenv env topValInfo vFlags (tpenv, names, takenNames) ty p | _ -> try - let c' = TcConst cenv ty m env c + let c' = TcConst cenv (MustEqual ty) m env c (fun _ -> TPat_const (c', m)), (tpenv, names, takenNames) with e -> errorRecovery e m @@ -4978,7 +4991,7 @@ and TcPat warnOnUpper cenv env topValInfo vFlags (tpenv, names, takenNames) ty p let activePatType = apinfo.OverallType cenv.g m ty activePatResTys 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 @@ -5251,21 +5264,20 @@ and UnifyTypesAndRecover cenv env m expectedTy actualTy = 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 (e: SynExpr) = 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' + AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css e.Range NoTrace desiredTy argty + let e', tpenv = TcExpr cenv (MustEqual argty) env tpenv e + let e' = mkCoerceIfNeeded cenv.g desiredTy argty e' e', tpenv else - TcExpr cenv ty env tpenv e - + TcExpr cenv (MustConvertTo desiredTy) env tpenv e and TcExpr cenv ty (env: TcEnv) tpenv (expr: SynExpr) = // Start an error recovery handler @@ -5278,10 +5290,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. @@ -5291,7 +5303,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 @@ -5299,7 +5310,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 @@ -5348,7 +5359,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) -> @@ -5391,7 +5402,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) @@ -5409,16 +5420,30 @@ 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) = +and TcExprLeafProtectExcept p cenv (overallTy: OverallTy) (env: TcEnv) m f = + match overallTy with + | MustConvertTo(oty) when not (p oty) && isAppTy cenv.g oty -> + let oty2 = NewInferenceType() + AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace oty oty2 + let expr, tpenv = f (MustEqual oty2) + let expr2 = mkCoerceIfNeeded cenv.g oty oty2 expr + expr2, tpenv + | _ -> + f overallTy + +and TcExprLeafProtect cenv overallTy env m f = + TcExprLeafProtectExcept (fun _ -> false) cenv overallTy env m f + +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 @@ -5426,18 +5451,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 _ -> @@ -5463,10 +5488,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 // OPPORTUNITY: MustSubsumeSoft for range 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 resultTy) envinner tpenv clauses let overallExpr = mkMultiLambda m [idv1] ((mkLet spMatch m idv2 idve1 matchExpr), resultTy) overallExpr, tpenv @@ -5479,14 +5504,14 @@ 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 + UnifyTypes cenv env m overallTy.Commit tgtTy + let expr, tpenv = TcExpr cenv (MustConvertTo tgtTy) env tpenv synBodyExpr expr, 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 @@ -5504,10 +5529,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) @@ -5519,9 +5544,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 @@ -5531,32 +5556,51 @@ 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 (MustConvertTo 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 + // TODO: negative test cases: + (* + Negative: + + let x : (obj * obj) = (let p = (1, 2) in p) + Positive: + + let x : obj = (1,2) + let x : obj * obj = (1,2) + let x : (obj * obj) = (let x = 1 in let y = 2 in (x,y)) + let x : struct (obj * obj) = struct (1,2) + let x : (unit -> obj) = (fun () -> 1) + let x : (unit -> obj * obj) = (fun () -> (1,2)) + *) + TcExprLeafProtectExcept (isAnyTupleTy cenv.g) cenv overallTy env m (fun overallTy -> + let tupInfo, argTys = UnifyTupleTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv m overallTy.Commit 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) + TcExprLeafProtect 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) + TcExprLeafProtect cenv overallTy env m (fun overallTy -> + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) let argty = NewInferenceType () - UnifyTypes cenv env m overallTy (if isArray then mkArrayType cenv.g argty else mkListTy cenv.g argty) + UnifyTypes cenv env m overallTy.Commit (if isArray then mkArrayType cenv.g argty else mkListTy cenv.g argty) // Always allow subsumption if a nominal type is known prior to type checking any arguments let flex = not (isTyparTy cenv.g argty) @@ -5574,30 +5618,37 @@ 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) -> + TcExprLeafProtect cenv overallTy env mNewExpr (fun overallTy -> let objTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.Use env tpenv synObjTy - UnifyTypes cenv env mNewExpr overallTy objTy + UnifyTypes cenv env mNewExpr overallTy.Commit objTy 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) + TcExprLeafProtect cenv overallTy env m (fun overallTy -> + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.eAccessRights) TcObjectExpr cenv overallTy env tpenv (objTy, argopt, binds, extraImpls, mNewExpr, m) + ) | SynExpr.Record (inherits, optOrigExpr, flds, mWholeExpr) -> - CallExprHasTypeSink cenv.tcSink (mWholeExpr, env.NameEnv, overallTy, env.AccessRights) + TcExprLeafProtect cenv overallTy env mWholeExpr (fun overallTy -> + CallExprHasTypeSink cenv.tcSink (mWholeExpr, env.NameEnv, overallTy.Commit, env.AccessRights) 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.tcSink m idv env @@ -5614,12 +5665,16 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = TcForEachExpr cenv overallTy env tpenv (pat, enumSynExpr, bodySynExpr, m, spForLoop) | SynExpr.CompExpr (isArrayOrList, isNotNakedRefCell, comp, m) -> + TcExprLeafProtect cenv overallTy env m (fun overallTy -> let env = ExitFamilyRegion env - cenv.TcSequenceExpressionEntry cenv env overallTy tpenv (isArrayOrList, isNotNakedRefCell, comp) m + cenv.TcSequenceExpressionEntry cenv env overallTy.Commit tpenv (isArrayOrList, isNotNakedRefCell, comp) m + ) | SynExpr.ArrayOrListOfSeqExpr (isArray, comp, m) -> - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.eAccessRights) - cenv.TcArrayOrListSequenceExpression cenv env overallTy tpenv (isArray, comp) m + TcExprLeafProtect cenv overallTy env m (fun overallTy -> + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.eAccessRights) + cenv.TcArrayOrListSequenceExpression cenv env overallTy.Commit tpenv (isArray, comp) m + ) | SynExpr.LetOrUse _ -> TcLinearExprs (TcExprThatCanBeCtorBody cenv) cenv env overallTy tpenv false synExpr (fun x -> x) @@ -5628,36 +5683,36 @@ and TcExprUndelayed cenv overallTy env tpenv (synExpr: SynExpr) = 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 (Clause(pat, optWhenExpr, _, m, _)) -> Clause(pat, optWhenExpr, (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 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 @@ -5684,7 +5739,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 _ -> @@ -5739,6 +5794,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) -> + TcExprLeafProtect cenv overallTy env m (fun overallTy -> 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 @@ -5750,21 +5806,24 @@ 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 + UnifyTypes cenv env m overallTy.Commit returnTy Expr.Op (TOp.TraitCall traitInfo, [], args', m), tpenv + ) | SynExpr.LibraryOnlyUnionCaseFieldGet (e1, c, n, m) -> + TcExprLeafProtect cenv overallTy env m (fun overallTy -> 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 + UnifyTypes cenv env m overallTy.Commit ty2 mkf n, 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' -> @@ -5773,7 +5832,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) -> @@ -5782,18 +5841,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) @@ -5820,12 +5879,12 @@ 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 // TODO: OPPORTUNITY 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) let envinner = if isMember then envinner else ExitFamilyRegion envinner - let bodyExpr, tpenv = TcIteratedLambdas cenv false envinner resultTy takenNames tpenv bodyExpr + let bodyExpr, tpenv = TcIteratedLambdas cenv false envinner (MustConvertTo 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))) @@ -5833,7 +5892,6 @@ 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) @@ -6060,10 +6118,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 @@ -6095,17 +6153,17 @@ 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: OverallTy) env tpenv optOrigExprInfo objTy fldsList m = let tcref, tinst = destAppTy cenv.g objTy let tycon = tcref.Deref - UnifyTypes cenv env m overallTy objTy + UnifyTypes cenv env m overallTy.Commit objTy // Types with implicit constructors can't use record or object syntax: all constructions must go through the implicit constructor if tycon.MembersOfFSharpTyconByName |> NameMultiMap.existsInRange (fun v -> v.IsIncrClassConstructor) then @@ -6417,7 +6475,7 @@ and CheckSuperType cenv ty m = errorR(Error(FSComp.SR.tcCannotInheritFromErasedType(), m)) -and TcObjectExpr cenv overallTy env tpenv (synObjTy, argopt, binds, extraImpls, mNewExpr, mWholeExpr) = +and TcObjectExpr cenv (overallTy: OverallTy) env tpenv (synObjTy, argopt, binds, extraImpls, mNewExpr, mWholeExpr) = let mObjTy = synObjTy.Range let objTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synObjTy @@ -6468,6 +6526,8 @@ and TcObjectExpr cenv overallTy env tpenv (synObjTy, argopt, binds, extraImpls, errorR(Error(FSComp.SR.tcCannotInheritFromErasedType(), m)) (m, intfTy, overrides), tpenv) + let overallTy = overallTy.Commit // TODO: { new SubType() ... } should be enough for MustConvertTo base + let realObjTy = if isObjTy cenv.g objTy && not (isNil extraImpls) then (p23 (List.head extraImpls)) else objTy UnifyTypes cenv env mWholeExpr overallTy realObjTy @@ -6478,7 +6538,7 @@ and TcObjectExpr cenv overallTy env tpenv (synObjTy, argopt, binds, extraImpls, let afterResolution = ForNewConstructors cenv.tcSink env synObjTy.Range 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 @@ -6551,8 +6611,9 @@ and TcObjectExpr cenv overallTy env tpenv (synObjTy, argopt, binds, extraImpls, //------------------------------------------------------------------------- /// 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 = + let overallTy = overallTy.Commit // TODO: { new SubType() ... } should be enough for MustConvertTo base if (AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy cenv.g.string_ty) then mkString cenv.g m s, tpenv else @@ -6595,7 +6656,8 @@ and TcFormatStringExpr cenv overallTy env m tpenv (fmtString: string) = 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 overallTy = overallTy.Commit // TODO: { new SubType() ... } should be enough for MustConvertTo base let g = cenv.g let synFillExprs = @@ -6733,7 +6795,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) @@ -6758,7 +6820,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) @@ -6780,16 +6842,16 @@ 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) + UnifyTypes cenv env m overallTy.Commit (mkByteArrayTy cenv.g) 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 + UnifyTypes cenv env m overallTy.Commit (mkArrayType cenv.g cenv.g.uint16_ty); Expr.Op (TOp.UInt16s arr, [], [], m), tpenv | SynConst.UserNum (s, suffix) -> let expr = @@ -6825,8 +6887,7 @@ and TcConstExpr cenv overallTy env m tpenv c = | _ -> let c' = TcConst cenv overallTy m env c - Expr.Const (c', m, overallTy), tpenv - + Expr.Const (c', m, overallTy.Commit), tpenv //------------------------------------------------------------------------- // TcAssertExpr @@ -6842,7 +6903,8 @@ 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: OverallTy) env tpenv (inherits, optOrigExpr, flds, mWholeExpr) = + let overallTy = overallTy.Commit // TODO: a record expression should be enough to satisfy MustConvertTo for any of its supertypes let requiresCtor = (GetCtorShapeCounter env = 1) // Get special expression forms for constructors let haveCtor = Option.isSome inherits @@ -6854,7 +6916,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 @@ -6912,7 +6974,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 @@ -6924,7 +6986,7 @@ and TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr errorR(InternalError("Unexpected failure in getting super type", mWholeExpr)) None, tpenv - let expr, tpenv = TcRecordConstruction cenv overallTy env tpenv optOrigExprInfo overallTy fldsList mWholeExpr + let expr, tpenv = TcRecordConstruction cenv (MustEqual overallTy) env tpenv optOrigExprInfo overallTy fldsList mWholeExpr let expr = match superTy with @@ -6935,13 +6997,13 @@ 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: OverallTy) env tpenv (isStruct, optOrigSynExpr, unsortedFieldIdsAndSynExprsGiven, mWholeExpr) = let unsortedFieldSynExprsGiven = List.map snd unsortedFieldIdsAndSynExprsGiven match optOrigSynExpr with | None -> let unsortedFieldIds = unsortedFieldIdsAndSynExprsGiven |> List.map fst |> List.toArray - let anonInfo, sortedFieldTys = UnifyAnonRecdTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv mWholeExpr overallTy isStruct unsortedFieldIds + let anonInfo, sortedFieldTys = UnifyAnonRecdTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv mWholeExpr overallTy.Commit isStruct unsortedFieldIds // Sort into canonical order let sortedIndexedArgs = @@ -6965,7 +7027,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 @@ -6980,7 +7042,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 @@ -7018,7 +7080,7 @@ and TcAnonRecdExpr cenv overallTy env tpenv (isStruct, optOrigSynExpr, unsortedF let unsortedFieldIdsAll = Array.map fst unsortedIdAndExprsAll - let anonInfo, sortedFieldTysAll = UnifyAnonRecdTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv mWholeExpr overallTy isStruct unsortedFieldIdsAll + let anonInfo, sortedFieldTysAll = UnifyAnonRecdTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv mWholeExpr overallTy.Commit isStruct unsortedFieldIdsAll let sortedIndexedFieldsAll = unsortedIdAndExprsAll |> Array.indexed |> Array.sortBy (snd >> fst >> textOfId) @@ -7050,7 +7112,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 @@ -7095,7 +7157,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 @@ -7180,7 +7242,7 @@ and TcForEachExpr cenv overallTy env tpenv (pat, enumSynExpr, bodySynExpr, mWhol cenv env enumSynExpr.Range pat.Range false IgnoreWithWarning (elemVar, [], None) [TClause(pat, None, TTarget(valsDefinedByMatching, bodyExpr, DebugPointForTarget.Yes), mForLoopStart)] enumElemTy - overallTy + overallTy.Commit // Apply the fixup to bind the elemVar if needed let bodyExpr = bodyExprFixup elemVar bodyExpr @@ -7225,13 +7287,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 @@ -7249,7 +7311,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 @@ -7264,13 +7326,16 @@ 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 + match overallTy with + | MustConvertTo(oty) when AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css mExpr oty exprty -> () + | _ -> UnifyTypesAndRecover cenv env mExpr overallTy.Commit exprty | DelayedDot :: _ | DelayedSet _ :: _ @@ -7305,26 +7370,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. @@ -7334,8 +7399,14 @@ 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 + match overallTy with + | MustConvertTo(oty) when AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css mExpr oty exprty -> + mkCoerceIfNeeded cenv.g oty exprty expr.Expr, tpenv + | _ -> + UnifyTypes cenv env mExpr overallTy.Commit exprty + expr.Expr, 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 @@ -7349,7 +7420,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 @@ -7416,7 +7487,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 | _ -> @@ -7473,7 +7544,7 @@ and TcNameOfExpr cenv env tpenv (synArg: SynExpr) = // 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 + check (Some (MustEqual tgtTy)) resultOpt synBodyExpr delayed | _ -> error (Error(FSComp.SR.expressionHasNoName(), m)) @@ -7489,7 +7560,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 @@ -7515,7 +7586,7 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( | _ -> false) | _ -> () - let arg, tpenv = TcExpr cenv domainTy env tpenv synArg + let arg, tpenv = TcExpr cenv (MustEqual domainTy) env tpenv synArg let exprAndArg, resultTy = buildApp cenv expr resultTy arg mExprAndArg TcDelayed cenv overallTy env tpenv mExprAndArg exprAndArg resultTy atomicFlag delayed @@ -7523,10 +7594,10 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( // OK, 'expr' doesn't have function type, but perhaps 'expr' is a computation expression builder, and 'arg' is '{ ... }' match synArg with | SynExpr.CompExpr (false, _isNotNakedRefCell, comp, _m) -> - let bodyOfCompExpr, tpenv = cenv.TcComputationExpression cenv env overallTy tpenv (mFunExpr, expr.Expr, exprty, comp) + let bodyOfCompExpr, tpenv = cenv.TcComputationExpression cenv env overallTy.Commit 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 @@ -7548,7 +7619,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 @@ -7561,7 +7632,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 @@ -7602,7 +7673,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 + UnifyTypes cenv env mExprAndArg overallTy.Commit ucaseAppTy let numArgs = List.length args UnionCaseOrExnCheck env numArgTys numArgs mExprAndArg @@ -7676,7 +7747,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' -> @@ -7945,9 +8016,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 @@ -7977,7 +8048,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 @@ -8048,7 +8119,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 @@ -8078,7 +8149,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' @@ -8115,7 +8186,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 @@ -8231,7 +8302,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 @@ -8264,7 +8335,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 @@ -8295,7 +8366,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' @@ -8364,8 +8435,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" @@ -8389,7 +8461,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 = @@ -8404,7 +8476,9 @@ and TcMethodApplicationThen // Resolve the "delayed" lookups let exprty = (tyOfExpr cenv.g expr) - PropagateThenTcDelayed cenv overallTy env tpenv mWholeExpr (MakeApplicableExprNoFlex cenv expr) exprty atomicFlag delayed + TcExprLeafProtect cenv overallTy env m (fun overallTy -> + PropagateThenTcDelayed cenv overallTy env tpenv mWholeExpr (MakeApplicableExprNoFlex cenv expr) exprty atomicFlag delayed + ) /// Infer initial type information at the callsite from the syntax of an argument, prior to overload resolution. and GetNewInferenceTypeForMethodArg cenv env tpenv x = @@ -8428,7 +8502,7 @@ and TcMethodApplication mMethExpr // range of the entire method expression mItem methodName - (objTyOpt: TType option) + (objTyOpt: TType option) ad mut isProp @@ -8436,7 +8510,7 @@ and TcMethodApplication afterResolution isSuperInit curriedCallerArgs - exprTy + (exprTy: OverallTy) delayed = @@ -8454,7 +8528,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)) @@ -8528,9 +8602,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 @@ -8587,10 +8661,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 // TODO: opportunity // "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 @@ -8598,7 +8672,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 // TODO: important opportunity here 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 = @@ -8608,7 +8682,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 // TODO: opprtunity | Some (unnamedCurriedCallerArgs, namedCurriedCallerArgs), _ -> let unnamedCurriedCallerArgs = unnamedCurriedCallerArgs |> List.mapSquared (fun (argExpr, argTy, mArg) -> CallerArg(argTy, mArg, false, argExpr)) @@ -8635,7 +8709,7 @@ and TcMethodApplication yield makeOneCalledMeth (minfo, pinfoOpt, false) ] let uniquelyResolved = - UnifyUniqueOverloading denv cenv.css mMethExpr callerArgCounts methodName ad preArgumentTypeCheckingCalledMethGroup returnTy + UnifyUniqueOverloading denv cenv.css mMethExpr callerArgCounts methodName ad preArgumentTypeCheckingCalledMethGroup returnTy.Commit // TODO: don't commit here uniquelyResolved, preArgumentTypeCheckingCalledMethGroup @@ -8657,9 +8731,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, MustConvertTo returnTy | _ -> - let domainTy, returnTy = UnifyFunctionType None cenv denv mMethExpr exprTy + let domainTy, returnTy = UnifyFunctionType None cenv denv mMethExpr exprTy.Commit // TODO: opportunity 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 = @@ -8667,7 +8742,7 @@ and TcMethodApplication argTys else [domainTy] - [argTys], returnTy + [argTys], MustConvertTo returnTy // TODO check me 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)) @@ -8733,7 +8808,8 @@ and TcMethodApplication (//freeInTypeLeftToRight cenv.g false returnTy @ (unnamedCurriedCallerArgs |> List.collectSquared (fun callerArg -> freeInTypeLeftToRight cenv.g false callerArg.CallerArgumentType))) - let result, errors = ResolveOverloadingForCall denv cenv.css mMethExpr methodName 0 None callerArgs ad postArgumentTypeCheckingCalledMethGroup true (Some returnTy) + // TODO: opporutnity to remove commit + let result, errors = ResolveOverloadingForCall denv cenv.css mMethExpr methodName 0 None callerArgs ad postArgumentTypeCheckingCalledMethGroup true (Some returnTy.Commit) match afterResolution, result with | AfterResolution.DoNothing, _ -> () @@ -8900,7 +8976,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)) @@ -9017,7 +9093,7 @@ and TcMethodArg cenv env (lambdaPropagationInfo, tpenv) (lambdaPropagationInfoFo | _ -> () loop argTy 0 - let e', tpenv = TcExpr cenv argTy env tpenv argExpr + let e', tpenv = TcExpr cenv (MustEqual argTy) env tpenv argExpr // After we have checked, propagate the info from argument into the overloads that receive it. // @@ -9036,9 +9112,10 @@ 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 + // TODO: delegate expr should be enough for any of delegate supertypes + 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 @@ -9100,10 +9177,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 @@ -9114,7 +9191,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 @@ -9122,14 +9199,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)) | _ -> @@ -9138,7 +9215,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) = @@ -9149,17 +9226,17 @@ 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 (Clause(pat, optWhenExpr, e, patm, spTgt)) = +and TcMatchClause cenv inputTy (resultTy: OverallTy) env isFirst tpenv (Clause(pat, optWhenExpr, e, patm, spTgt)) = 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 @@ -9405,8 +9482,8 @@ and TcNormalizedBinding declKind (cenv: cenv) env tpenv overallTy safeThisValOpt conditionallySuppressErrorReporting atTopNonLambdaDefn (fun () -> - 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 overallExprTy) envinner tpenv rhsExpr) if bkind = StandaloneExpression && not cenv.isScript then UnifyUnitType cenv env mBinding overallPatTy rhsExprChecked |> ignore @@ -9443,7 +9520,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 @@ -9590,7 +9667,7 @@ and TcAttribute canFail cenv (env: TcEnv) attrTgt (synAttr: SynAttribute) = 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 (NewInferenceType ())) [] UnifyTypes cenv env mAttr ty (tyOfExpr cenv.g expr) diff --git a/src/fsharp/CheckExpressions.fsi b/src/fsharp/CheckExpressions.fsi index 06a135f3111..33d4cf72b88 100644 --- a/src/fsharp/CheckExpressions.fsi +++ b/src/fsharp/CheckExpressions.fsi @@ -159,6 +159,17 @@ val TcFieldInit : range -> ILFieldInit -> Const val LightweightTcValForUsingInBuildMethodCall : g : TcGlobals -> vref:ValRef -> vrefFlags : ValUseFlag -> vrefTypeInst : TTypes -> m : range -> Expr * TType +/// 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 ty: TType + + /// Represents a point where no subsumption/widening is possible + member Commit: TType + //------------------------------------------------------------------------- // The rest are all helpers needed for declaration checking (CheckDeclarations.fs) //------------------------------------------------------------------------- @@ -649,28 +660,28 @@ 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:OverallTy -> 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 -> e:SynExpr -> 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 From 722bd32903726e952af95971546cd8e9279d3d23 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Fri, 15 Jan 2021 15:29:57 +0000 Subject: [PATCH 02/42] merge main --- src/fsharp/CheckComputationExpressions.fs | 33 ++++++++++--------- src/fsharp/CheckComputationExpressions.fsi | 6 ++-- src/fsharp/CheckExpressions.fs | 38 +++++++++++----------- src/fsharp/CheckExpressions.fsi | 12 +++---- 4 files changed, 45 insertions(+), 44 deletions(-) diff --git a/src/fsharp/CheckComputationExpressions.fs b/src/fsharp/CheckComputationExpressions.fs index a8bd308b7ed..3383ca42585 100644 --- a/src/fsharp/CheckComputationExpressions.fs +++ b/src/fsharp/CheckComputationExpressions.fs @@ -215,8 +215,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 // TODO: a computation expression should be enough for MustConvertTo 'obj' etc. + //dprintfn "TcComputationExpression, comp = \n%A\n-------------------\n" comp let ad = env.eAccessRights @@ -1616,7 +1617,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) @@ -1679,10 +1680,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) @@ -1735,7 +1736,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 @@ -1745,7 +1746,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 let unwindExprMark = unwindExpr.Range let unwindExpr = mkUnitDelayLambda cenv.g unwindExprMark unwindExpr @@ -1777,7 +1778,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 @@ -1786,7 +1787,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 @@ -1800,7 +1801,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 inputExprMark = inputExpr.Range let matchv, matchExpr = compileSeqExprMatchClauses cenv env inputExprMark (pat', vspecs) innerExpr (Some inputExpr) bindPatTy genOuterTy @@ -1847,7 +1848,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 -> @@ -1877,11 +1878,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 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 @@ -1931,12 +1932,12 @@ let TcArrayOrListSequenceExpression (cenv: cenv) env overallTy tpenv (isArray, c let genCollTy = (if isArray then mkArrayType else mkListTy) cenv.g genCollElemTy - UnifyTypes cenv env m overallTy genCollTy + UnifyTypes cenv env m overallTy.Commit genCollTy 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 @@ -1948,7 +1949,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 diff --git a/src/fsharp/CheckComputationExpressions.fsi b/src/fsharp/CheckComputationExpressions.fsi index c4265c8697a..73477cd671c 100644 --- a/src/fsharp/CheckComputationExpressions.fsi +++ b/src/fsharp/CheckComputationExpressions.fsi @@ -8,9 +8,9 @@ open FSharp.Compiler.Text open FSharp.Compiler.Text.Range 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/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 9a33f3a3092..4f85f9d39e6 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -347,6 +347,19 @@ let TryFindUnscopedTypar n (UnscopedTyparEnv tab) = Map.tryFind n tab let HideUnscopedTypars typars (UnscopedTyparEnv tab) = UnscopedTyparEnv (List.fold (fun acc (tp: Typar) -> Map.remove tp.Name acc) tab typars) +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 ty: TType + + /// Represents a point where no subsumption/widening is possible + member x.Commit = + match x with + | MustEqual ty -> ty + | MustConvertTo ty -> ty + /// Represents the compilation environment for typechecking a single file in an assembly. [] type TcFileState = @@ -404,11 +417,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 } /// Create a new compilation environment @@ -513,19 +526,6 @@ let LocateEnv ccu env enclosingNamespacePath = let env = { env with eNameResEnv = { env.NameEnv with eDisplayEnv = env.DisplayEnv.AddOpenPath (pathOfLid env.ePath) } } env -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 ty: TType - - /// Represents a point where no subsumption/widening is possible - member x.Commit = - match x with - | MustEqual ty -> ty - | MustConvertTo ty -> ty - //------------------------------------------------------------------------- // Helpers for unification //------------------------------------------------------------------------- @@ -5667,13 +5667,13 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = | SynExpr.CompExpr (isArrayOrList, isNotNakedRefCell, comp, m) -> TcExprLeafProtect cenv overallTy env m (fun overallTy -> let env = ExitFamilyRegion env - cenv.TcSequenceExpressionEntry cenv env overallTy.Commit tpenv (isArrayOrList, isNotNakedRefCell, comp) m + cenv.TcSequenceExpressionEntry cenv env overallTy tpenv (isArrayOrList, isNotNakedRefCell, comp) m ) | SynExpr.ArrayOrListOfSeqExpr (isArray, comp, m) -> TcExprLeafProtect cenv overallTy env m (fun overallTy -> CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.eAccessRights) - cenv.TcArrayOrListSequenceExpression cenv env overallTy.Commit tpenv (isArray, comp) m + cenv.TcArrayOrListSequenceExpression cenv env overallTy tpenv (isArray, comp) m ) | SynExpr.LetOrUse _ -> @@ -7594,7 +7594,7 @@ and TcFunctionApplicationThen cenv (overallTy: OverallTy) env tpenv mExprAndArg // OK, 'expr' doesn't have function type, but perhaps 'expr' is a computation expression builder, and 'arg' is '{ ... }' match synArg with | SynExpr.CompExpr (false, _isNotNakedRefCell, comp, _m) -> - let bodyOfCompExpr, tpenv = cenv.TcComputationExpression cenv env overallTy.Commit tpenv (mFunExpr, expr.Expr, exprty, comp) + 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.Commit, mFunExpr, mArg)) diff --git a/src/fsharp/CheckExpressions.fsi b/src/fsharp/CheckExpressions.fsi index 33d4cf72b88..5157db81a0f 100644 --- a/src/fsharp/CheckExpressions.fsi +++ b/src/fsharp/CheckExpressions.fsi @@ -235,11 +235,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 * @@ -254,11 +254,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. From 983c71bca532262c56034c06f32614db1b7e981c Mon Sep 17 00:00:00 2001 From: Don Syme Date: Fri, 15 Jan 2021 18:59:12 +0000 Subject: [PATCH 03/42] fix some misc bits and pieces --- src/fsharp/CheckComputationExpressions.fsi | 4 +- src/fsharp/CheckDeclarations.fs | 2 +- src/fsharp/CheckExpressions.fs | 202 ++++++++++----------- src/fsharp/CheckExpressions.fsi | 13 +- src/fsharp/ConstraintSolver.fs | 32 +++- src/fsharp/ConstraintSolver.fsi | 15 +- 6 files changed, 137 insertions(+), 131 deletions(-) diff --git a/src/fsharp/CheckComputationExpressions.fsi b/src/fsharp/CheckComputationExpressions.fsi index 73477cd671c..1ca2dc14703 100644 --- a/src/fsharp/CheckComputationExpressions.fsi +++ b/src/fsharp/CheckComputationExpressions.fsi @@ -3,12 +3,12 @@ module internal FSharp.Compiler.CheckComputationExpressions open FSharp.Compiler.CheckExpressions +open FSharp.Compiler.ConstraintSolver open FSharp.Compiler.SyntaxTree open FSharp.Compiler.Text -open FSharp.Compiler.Text.Range open FSharp.Compiler.TypedTree -val TcSequenceExpressionEntry: cenv:TcFileState -> env:TcEnv -> overallTy:OverallTy -> 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:OverallTy -> tpenv:UnscopedTyparEnv -> isArray:bool * comp:SynExpr -> m:range -> Expr * UnscopedTyparEnv diff --git a/src/fsharp/CheckDeclarations.fs b/src/fsharp/CheckDeclarations.fs index 5733544662d..6d2d38ef198 100644 --- a/src/fsharp/CheckDeclarations.fs +++ b/src/fsharp/CheckDeclarations.fs @@ -521,7 +521,7 @@ module TcRecdUnionAndEnumDeclarations = | SynConst.UInt16s _ | SynConst.UserNum _ -> error(Error(FSComp.SR.tcInvalidEnumerationLiteral(), m)) | _ -> - let v = TcConst cenv (MustEqual fieldTy) m env v + let v = TcConst cenv fieldTy m env v let vis, _ = ComputeAccessAndCompPath env None m None None parent let vis = CombineReprAccess parent vis if id.idText = "value__" then errorR(Error(FSComp.SR.tcNotValidEnumCaseName(), id.idRange)) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 4f85f9d39e6..14196bd129c 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -347,19 +347,6 @@ let TryFindUnscopedTypar n (UnscopedTyparEnv tab) = Map.tryFind n tab let HideUnscopedTypars typars (UnscopedTyparEnv tab) = UnscopedTyparEnv (List.fold (fun acc (tp: Typar) -> Map.remove tp.Name acc) tab typars) -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 ty: TType - - /// Represents a point where no subsumption/widening is possible - member x.Commit = - match x with - | MustEqual ty -> ty - | MustConvertTo ty -> ty - /// Represents the compilation environment for typechecking a single file in an assembly. [] type TcFileState = @@ -418,8 +405,10 @@ type TcFileState = isInternalTestSpanStackReferring: bool // forward call TcSequenceExpressionEntry: TcFileState -> TcEnv -> OverallTy -> UnscopedTyparEnv -> bool * bool ref * SynExpr -> range -> Expr * UnscopedTyparEnv + // forward call TcArrayOrListSequenceExpression: TcFileState -> TcEnv -> OverallTy -> UnscopedTyparEnv -> bool * SynExpr -> range -> Expr * UnscopedTyparEnv + // forward call TcComputationExpression: TcFileState -> TcEnv -> OverallTy -> UnscopedTyparEnv -> range * Expr * TType * SynExpr -> Expr * UnscopedTyparEnv } @@ -464,6 +453,36 @@ let CopyAndFixupTypars m rigid tpsorig = let UnifyTypes cenv (env: TcEnv) m actualTy expectedTy = ConstraintSolver.AddCxTypeEqualsType env.eContextInfo env.DisplayEnv cenv.css m (tryNormalizeMeasureInType cenv.g actualTy) (tryNormalizeMeasureInType cenv.g expectedTy) +// If the overall type admits subsumption, and the original unify would have failed, +// then allow subsumption. +let UnifyOverallType cenv (env: TcEnv) m overallTy actualTy = + match overallTy with + | MustConvertTo(overallTy) when isAppTy cenv.g overallTy && not (isSealedTy cenv.g overallTy) -> + let actualTy = tryNormalizeMeasureInType cenv.g actualTy + let overallTy = tryNormalizeMeasureInType cenv.g overallTy + if AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy actualTy then + () + elif AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy actualTy then + () + else + UnifyTypes cenv env m actualTy overallTy + | _ -> + UnifyTypes cenv env m actualTy overallTy.Commit + +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] @@ -755,8 +774,7 @@ let rec TcSynRationalConst c = | SynRationalConst.Rational(p, q, _) -> DivRational (intToRational p) (intToRational q) /// Typecheck constant terms in expressions and patterns -let TcConst cenv (overallTy: OverallTy) m env c = - let overallTy = overallTy.Commit // TODO: opportunities for subsumption and widening here +let TcConst cenv (overallTy: TType) m env c = let rec tcMeasure ms = match ms with | SynMeasure.One -> Measure.One @@ -4817,7 +4835,7 @@ and TcPat warnOnUpper cenv env topValInfo vFlags (tpenv, names, takenNames) ty p | _ -> try - let c' = TcConst cenv (MustEqual ty) m env c + let c' = TcConst cenv ty m env c (fun _ -> TPat_const (c', m)), (tpenv, names, takenNames) with e -> errorRecovery e m @@ -5254,14 +5272,6 @@ 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 (MustEqual exprty) env tpenv expr @@ -5425,14 +5435,14 @@ and TcExprUndelayedNoType cenv env tpenv synExpr: Expr * TType * _ = and TcExprLeafProtectExcept p cenv (overallTy: OverallTy) (env: TcEnv) m f = match overallTy with - | MustConvertTo(oty) when not (p oty) && isAppTy cenv.g oty -> + | MustConvertTo(oty) when not (p oty) && isAppTy cenv.g oty && not (isSealedTy cenv.g oty) -> let oty2 = NewInferenceType() AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace oty oty2 - let expr, tpenv = f (MustEqual oty2) + let expr, tpenv = f oty2 let expr2 = mkCoerceIfNeeded cenv.g oty oty2 expr expr2, tpenv | _ -> - f overallTy + f overallTy.Commit and TcExprLeafProtect cenv overallTy env m f = TcExprLeafProtectExcept (fun _ -> false) cenv overallTy env m f @@ -5450,20 +5460,26 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = | SynExpr.DotIndexedGet _ | SynExpr.DotIndexedSet _ | 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.Commit, env.AccessRights) - TcConstStringExpr cenv overallTy env m tpenv s + | SynExpr.Const (SynConst.String (s, m), mWholeExpr) -> + TcExprLeafProtect cenv overallTy env mWholeExpr (fun overallTy -> + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights) + TcConstStringExpr cenv overallTy env m tpenv s + ) | SynExpr.InterpolatedString (parts, m) -> - checkLanguageFeatureError cenv.g.langVersion LanguageFeature.StringInterpolation m + TcExprLeafProtect cenv overallTy env m (fun overallTy -> + checkLanguageFeatureError cenv.g.langVersion LanguageFeature.StringInterpolation m - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights) - TcInterpolatedStringExpr cenv overallTy env m tpenv parts + TcInterpolatedStringExpr cenv overallTy env m tpenv parts + ) | SynExpr.Const (synConst, m) -> - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) - TcConstExpr cenv overallTy env m tpenv synConst + TcExprLeafProtect cenv overallTy env m (fun overallTy -> + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights) + TcConstExpr cenv overallTy env m tpenv synConst + ) | SynExpr.Lambda _ -> TcIteratedLambdas cenv true env overallTy Set.empty tpenv synExpr @@ -5567,22 +5583,8 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = expr, tpenv | SynExpr.Tuple (isExplicitStruct, args, _, m) -> - // TODO: negative test cases: - (* - Negative: - - let x : (obj * obj) = (let p = (1, 2) in p) - Positive: - - let x : obj = (1,2) - let x : obj * obj = (1,2) - let x : (obj * obj) = (let x = 1 in let y = 2 in (x,y)) - let x : struct (obj * obj) = struct (1,2) - let x : (unit -> obj) = (fun () -> 1) - let x : (unit -> obj * obj) = (fun () -> (1,2)) - *) TcExprLeafProtectExcept (isAnyTupleTy cenv.g) cenv overallTy env m (fun overallTy -> - let tupInfo, argTys = UnifyTupleTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv m overallTy.Commit isExplicitStruct args + 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 @@ -5597,10 +5599,10 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = | SynExpr.ArrayOrList (isArray, args, m) -> TcExprLeafProtect cenv overallTy env m (fun overallTy -> - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights) let argty = NewInferenceType () - UnifyTypes cenv env m overallTy.Commit (if isArray then mkArrayType cenv.g argty else mkListTy cenv.g argty) + UnifyTypes cenv env m overallTy (if isArray then mkArrayType cenv.g argty else mkListTy cenv.g argty) // Always allow subsumption if a nominal type is known prior to type checking any arguments let flex = not (isTyparTy cenv.g argty) @@ -5623,19 +5625,19 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = | SynExpr.New (superInit, synObjTy, arg, mNewExpr) -> TcExprLeafProtect cenv overallTy env mNewExpr (fun overallTy -> let objTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.Use env tpenv synObjTy - UnifyTypes cenv env mNewExpr overallTy.Commit objTy + UnifyTypes cenv env mNewExpr overallTy objTy TcNewExpr cenv env tpenv objTy (Some synObjTy.Range) superInit arg mNewExpr ) | SynExpr.ObjExpr (objTy, argopt, binds, extraImpls, mNewExpr, m) -> TcExprLeafProtect cenv overallTy env m (fun overallTy -> - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.eAccessRights) + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.eAccessRights) TcObjectExpr cenv overallTy env tpenv (objTy, argopt, binds, extraImpls, mNewExpr, m) ) | SynExpr.Record (inherits, optOrigExpr, flds, mWholeExpr) -> TcExprLeafProtect cenv overallTy env mWholeExpr (fun overallTy -> - CallExprHasTypeSink cenv.tcSink (mWholeExpr, env.NameEnv, overallTy.Commit, env.AccessRights) + CallExprHasTypeSink cenv.tcSink (mWholeExpr, env.NameEnv, overallTy, env.AccessRights) TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr) ) @@ -5667,13 +5669,13 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = | SynExpr.CompExpr (isArrayOrList, isNotNakedRefCell, comp, m) -> TcExprLeafProtect cenv overallTy env m (fun overallTy -> let env = ExitFamilyRegion env - cenv.TcSequenceExpressionEntry cenv env overallTy tpenv (isArrayOrList, isNotNakedRefCell, comp) m + cenv.TcSequenceExpressionEntry cenv env (MustEqual overallTy) tpenv (isArrayOrList, isNotNakedRefCell, comp) m ) | SynExpr.ArrayOrListOfSeqExpr (isArray, comp, m) -> TcExprLeafProtect cenv overallTy env m (fun overallTy -> - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.eAccessRights) - cenv.TcArrayOrListSequenceExpression cenv env overallTy tpenv (isArray, comp) m + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.eAccessRights) + cenv.TcArrayOrListSequenceExpression cenv env (MustEqual overallTy) tpenv (isArray, comp) m ) | SynExpr.LetOrUse _ -> @@ -5808,7 +5810,7 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = let flexes = argTys |> List.map (isTyparTy cenv.g >> not) let args', tpenv = TcExprsWithFlexes cenv env m tpenv flexes argTys args AddCxMethodConstraint env.DisplayEnv cenv.css m NoTrace traitInfo - UnifyTypes cenv env m overallTy.Commit returnTy + UnifyTypes cenv env m overallTy returnTy Expr.Op (TOp.TraitCall traitInfo, [], args', m), tpenv ) @@ -5818,7 +5820,7 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = 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.Commit ty2 + UnifyTypes cenv env m overallTy ty2 mkf n, tpenv ) @@ -5879,7 +5881,7 @@ and TcExprUndelayed cenv (overallTy: 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.Commit // TODO: OPPORTUNITY + 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) @@ -5893,7 +5895,6 @@ and TcIteratedLambdas cenv isFirst (env: TcEnv) overallTy takenNames tpenv e = // Dive into the expression to check for syntax errors and suppress them if they show. conditionallySuppressErrorReporting (not isFirst && synExprContainsError e) (fun () -> 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). @@ -6158,12 +6159,11 @@ and TcCtorCall isNaked cenv env tpenv (overallTy: OverallTy) objTy mObjTyOpt ite | _ -> error(Error(FSComp.SR.tcSyntaxCanOnlyBeUsedToCreateObjectTypes(if superInit then "inherit" else "new"), mWholeCall)) - // Check a record construction expression -and TcRecordConstruction cenv (overallTy: 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.Commit objTy + UnifyTypes cenv env m overallTy objTy // Types with implicit constructors can't use record or object syntax: all constructions must go through the implicit constructor if tycon.MembersOfFSharpTyconByName |> NameMultiMap.existsInRange (fun v -> v.IsIncrClassConstructor) then @@ -6475,7 +6475,7 @@ and CheckSuperType cenv ty m = errorR(Error(FSComp.SR.tcCannotInheritFromErasedType(), m)) -and TcObjectExpr cenv (overallTy: OverallTy) env tpenv (synObjTy, argopt, binds, extraImpls, mNewExpr, mWholeExpr) = +and TcObjectExpr cenv (overallTy: TType) env tpenv (synObjTy, argopt, binds, extraImpls, mNewExpr, mWholeExpr) = let mObjTy = synObjTy.Range let objTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synObjTy @@ -6526,8 +6526,6 @@ and TcObjectExpr cenv (overallTy: OverallTy) env tpenv (synObjTy, argopt, binds, errorR(Error(FSComp.SR.tcCannotInheritFromErasedType(), m)) (m, intfTy, overrides), tpenv) - let overallTy = overallTy.Commit // TODO: { new SubType() ... } should be enough for MustConvertTo base - let realObjTy = if isObjTy cenv.g objTy && not (isNil extraImpls) then (p23 (List.head extraImpls)) else objTy UnifyTypes cenv env mWholeExpr overallTy realObjTy @@ -6611,9 +6609,8 @@ and TcObjectExpr cenv (overallTy: OverallTy) env tpenv (synObjTy, argopt, binds, //------------------------------------------------------------------------- /// Check a constant string expression. It might be a 'printf' format string -and TcConstStringExpr cenv (overallTy: OverallTy) env m tpenv s = +and TcConstStringExpr cenv (overallTy: TType) env m tpenv s = - let overallTy = overallTy.Commit // TODO: { new SubType() ... } should be enough for MustConvertTo base if (AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy cenv.g.string_ty) then mkString cenv.g m s, tpenv else @@ -6656,8 +6653,7 @@ and TcFormatStringExpr cenv overallTy env m tpenv (fmtString: string) = mkString g m fmtString, tpenv /// Check an interpolated string expression -and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: SynInterpolatedStringPart list) = - let overallTy = overallTy.Commit // TODO: { new SubType() ... } should be enough for MustConvertTo base +and TcInterpolatedStringExpr cenv (overallTy: TType) env m tpenv (parts: SynInterpolatedStringPart list) = let g = cenv.g let synFillExprs = @@ -6842,16 +6838,16 @@ and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: Syn //------------------------------------------------------------------------- /// Check a constant expression. -and TcConstExpr cenv (overallTy: OverallTy) env m tpenv c = +and TcConstExpr cenv (overallTy: TType) env m tpenv c = match c with // NOTE: these aren't "really" constants | SynConst.Bytes (bytes, m) -> - UnifyTypes cenv env m overallTy.Commit (mkByteArrayTy cenv.g) + UnifyTypes cenv env m overallTy (mkByteArrayTy cenv.g) Expr.Op (TOp.Bytes bytes, [], [], m), tpenv | SynConst.UInt16s arr -> - UnifyTypes cenv env m overallTy.Commit (mkArrayType cenv.g cenv.g.uint16_ty); Expr.Op (TOp.UInt16s arr, [], [], m), tpenv + UnifyTypes cenv env m overallTy (mkArrayType cenv.g cenv.g.uint16_ty); Expr.Op (TOp.UInt16s arr, [], [], m), tpenv | SynConst.UserNum (s, suffix) -> let expr = @@ -6883,11 +6879,11 @@ and TcConstExpr cenv (overallTy: OverallTy) env m tpenv c = | _ -> expr - TcExpr cenv overallTy env tpenv expr + TcExpr cenv (MustEqual overallTy) env tpenv expr | _ -> let c' = TcConst cenv overallTy m env c - Expr.Const (c', m, overallTy.Commit), tpenv + Expr.Const (c', m, overallTy), tpenv //------------------------------------------------------------------------- // TcAssertExpr @@ -6903,8 +6899,7 @@ and TcAssertExpr cenv overallTy env (m: range) tpenv x = TcExpr cenv overallTy env tpenv callDiagnosticsExpr -and TcRecdExpr cenv (overallTy: OverallTy) env tpenv (inherits, optOrigExpr, flds, mWholeExpr) = - let overallTy = overallTy.Commit // TODO: a record expression should be enough to satisfy MustConvertTo for any of its supertypes +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 @@ -6986,7 +6981,7 @@ and TcRecdExpr cenv (overallTy: OverallTy) env tpenv (inherits, optOrigExpr, fld errorR(InternalError("Unexpected failure in getting super type", mWholeExpr)) None, tpenv - let expr, tpenv = TcRecordConstruction cenv (MustEqual overallTy) env tpenv optOrigExprInfo overallTy fldsList mWholeExpr + let expr, tpenv = TcRecordConstruction cenv overallTy env tpenv optOrigExprInfo overallTy fldsList mWholeExpr let expr = match superTy with @@ -6997,13 +6992,13 @@ and TcRecdExpr cenv (overallTy: OverallTy) env tpenv (inherits, optOrigExpr, fld // Check '{| .... |}' -and TcAnonRecdExpr cenv (overallTy: 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 | None -> let unsortedFieldIds = unsortedFieldIdsAndSynExprsGiven |> List.map fst |> List.toArray - let anonInfo, sortedFieldTys = UnifyAnonRecdTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv mWholeExpr overallTy.Commit isStruct unsortedFieldIds + let anonInfo, sortedFieldTys = UnifyAnonRecdTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv mWholeExpr overallTy isStruct unsortedFieldIds // Sort into canonical order let sortedIndexedArgs = @@ -7080,7 +7075,7 @@ and TcAnonRecdExpr cenv (overallTy: OverallTy) env tpenv (isStruct, optOrigSynEx let unsortedFieldIdsAll = Array.map fst unsortedIdAndExprsAll - let anonInfo, sortedFieldTysAll = UnifyAnonRecdTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv mWholeExpr overallTy.Commit isStruct unsortedFieldIdsAll + let anonInfo, sortedFieldTysAll = UnifyAnonRecdTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv mWholeExpr overallTy isStruct unsortedFieldIdsAll let sortedIndexedFieldsAll = unsortedIdAndExprsAll |> Array.indexed |> Array.sortBy (snd >> fst >> textOfId) @@ -7136,7 +7131,6 @@ and TcAnonRecdExpr cenv (overallTy: OverallTy) env tpenv (isStruct, optOrigSynEx 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 @@ -7333,9 +7327,7 @@ and Propagate cenv (overallTy: OverallTy) (env: TcEnv) tpenv (expr: ApplicableEx exprty // at the end of the application chain allow coercion introduction - match overallTy with - | MustConvertTo(oty) when AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css mExpr oty exprty -> () - | _ -> UnifyTypesAndRecover cenv env mExpr overallTy.Commit exprty + UnifyOverallTypeAndRecover cenv env mExpr overallTy exprty | DelayedDot :: _ | DelayedSet _ :: _ @@ -7400,12 +7392,8 @@ and TcDelayed cenv (overallTy: OverallTy) env tpenv mExpr expr exprty (atomicFla | [] | DelayedDot :: _ -> // at the end of the application chain allow coercion introduction - match overallTy with - | MustConvertTo(oty) when AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css mExpr oty exprty -> - mkCoerceIfNeeded cenv.g oty exprty expr.Expr, tpenv - | _ -> - UnifyTypes cenv env mExpr overallTy.Commit exprty - expr.Expr, tpenv + UnifyOverallTypeAndRecover cenv env mExpr overallTy exprty + mkCoerceIfNeeded cenv.g overallTy.Commit exprty expr.Expr, 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 @@ -8476,9 +8464,7 @@ and TcMethodApplicationThen // Resolve the "delayed" lookups let exprty = (tyOfExpr cenv.g expr) - TcExprLeafProtect cenv overallTy env m (fun overallTy -> - PropagateThenTcDelayed cenv overallTy env tpenv mWholeExpr (MakeApplicableExprNoFlex cenv expr) exprty atomicFlag delayed - ) + PropagateThenTcDelayed cenv overallTy env tpenv mWholeExpr (MakeApplicableExprNoFlex cenv expr) exprty atomicFlag delayed /// Infer initial type information at the callsite from the syntax of an argument, prior to overload resolution. and GetNewInferenceTypeForMethodArg cenv env tpenv x = @@ -8664,7 +8650,7 @@ and TcMethodApplication 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, MustEqual returnTy // TODO: opportunity + 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 @@ -8672,7 +8658,7 @@ and TcMethodApplication // type we assume the number of arguments is just "1". | None, _ -> - let domainTy, returnTy = UnifyFunctionType None cenv denv mMethExpr exprTy.Commit // TODO: important opportunity here + 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 = @@ -8682,7 +8668,7 @@ and TcMethodApplication [domainTy] let unnamedCurriedCallerArgs = [argTys |> List.map (fun ty -> CallerArg(ty, mMethExpr, false, dummyExpr)) ] let namedCurriedCallerArgs = unnamedCurriedCallerArgs |> List.map (fun _ -> []) - unnamedCurriedCallerArgs, namedCurriedCallerArgs, MustEqual returnTy // TODO: opprtunity + unnamedCurriedCallerArgs, namedCurriedCallerArgs, MustEqual returnTy | Some (unnamedCurriedCallerArgs, namedCurriedCallerArgs), _ -> let unnamedCurriedCallerArgs = unnamedCurriedCallerArgs |> List.mapSquared (fun (argExpr, argTy, mArg) -> CallerArg(argTy, mArg, false, argExpr)) @@ -8709,7 +8695,7 @@ and TcMethodApplication yield makeOneCalledMeth (minfo, pinfoOpt, false) ] let uniquelyResolved = - UnifyUniqueOverloading denv cenv.css mMethExpr callerArgCounts methodName ad preArgumentTypeCheckingCalledMethGroup returnTy.Commit // TODO: don't commit here + UnifyUniqueOverloading denv cenv.css mMethExpr callerArgCounts methodName ad preArgumentTypeCheckingCalledMethGroup returnTy uniquelyResolved, preArgumentTypeCheckingCalledMethGroup @@ -8732,9 +8718,9 @@ and TcMethodApplication // to their default values (for optionals) and be part of the return tuple (for out args). | [calledMeth] -> let curriedArgTys, returnTy = UnifyMatchingSimpleArgumentTypes exprTy.Commit calledMeth - curriedArgTys, MustConvertTo returnTy + curriedArgTys, MustEqual returnTy | _ -> - let domainTy, returnTy = UnifyFunctionType None cenv denv mMethExpr exprTy.Commit // TODO: opportunity + 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 = @@ -8742,7 +8728,7 @@ and TcMethodApplication argTys else [domainTy] - [argTys], MustConvertTo returnTy // TODO check me + [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)) @@ -8808,8 +8794,7 @@ and TcMethodApplication (//freeInTypeLeftToRight cenv.g false returnTy @ (unnamedCurriedCallerArgs |> List.collectSquared (fun callerArg -> freeInTypeLeftToRight cenv.g false callerArg.CallerArgumentType))) - // TODO: opporutnity to remove commit - let result, errors = ResolveOverloadingForCall denv cenv.css mMethExpr methodName 0 None callerArgs ad postArgumentTypeCheckingCalledMethGroup true (Some returnTy.Commit) + let result, errors = ResolveOverloadingForCall denv cenv.css mMethExpr methodName 0 None callerArgs ad postArgumentTypeCheckingCalledMethGroup true (Some returnTy) match afterResolution, result with | AfterResolution.DoNothing, _ -> () @@ -8848,7 +8833,6 @@ and TcMethodApplication | AfterResolution.RecordResolution(_, _, _, onFailure), None -> onFailure() - // Raise the errors from the constraint solving RaiseOperationResult errors match result with @@ -8958,9 +8942,12 @@ and TcMethodApplication let expr = mkCompGenLet mMethExpr objv expr (mkCompGenSequential mMethExpr propSetExpr objExpr) setterExprPrebinders, expr + // Subsumption to return type + let callExpr3b = mkCoerceIfNeeded cenv.g returnTy.Commit exprty callExpr3 + // Build the lambda expression if any, if the method is used as a first-class value let callExpr4 = - let expr = callExpr3 + let expr = callExpr3b match lambdaVars with | None -> expr | Some curriedLambdaVars -> @@ -9114,7 +9101,6 @@ and TcMethodArg cenv env (lambdaPropagationInfo, tpenv) (lambdaPropagationInfoFo /// Typecheck "new Delegate(fun x y z -> ...)" constructs and TcNewDelegateThen cenv (overallTy: OverallTy) env tpenv mDelTy mExprAndArg delegateTy arg atomicFlag delayed = let ad = env.eAccessRights - // TODO: delegate expr should be enough for any of delegate supertypes 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 diff --git a/src/fsharp/CheckExpressions.fsi b/src/fsharp/CheckExpressions.fsi index 5157db81a0f..5ae5a9cd8ec 100644 --- a/src/fsharp/CheckExpressions.fsi +++ b/src/fsharp/CheckExpressions.fsi @@ -159,17 +159,6 @@ val TcFieldInit : range -> ILFieldInit -> Const val LightweightTcValForUsingInBuildMethodCall : g : TcGlobals -> vref:ValRef -> vrefFlags : ValUseFlag -> vrefTypeInst : TTypes -> m : range -> Expr * TType -/// 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 ty: TType - - /// Represents a point where no subsumption/widening is possible - member Commit: TType - //------------------------------------------------------------------------- // The rest are all helpers needed for declaration checking (CheckDeclarations.fs) //------------------------------------------------------------------------- @@ -660,7 +649,7 @@ 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 -> overallTy:OverallTy -> 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:OverallTy -> env:TcEnv -> tpenv:UnscopedTyparEnv -> expr:SynExpr -> Expr * UnscopedTyparEnv diff --git a/src/fsharp/ConstraintSolver.fs b/src/fsharp/ConstraintSolver.fs index 32229f3271e..6d987bed4e5 100644 --- a/src/fsharp/ConstraintSolver.fs +++ b/src/fsharp/ConstraintSolver.fs @@ -208,6 +208,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 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 @@ -1564,7 +1577,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 -> @@ -2242,7 +2255,7 @@ and CanMemberSigsMatchUpToCheck 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 + (reqdRetTyOpt: OverallTy option) (calledMeth: CalledMeth<_>): ImperativeOperationResult = trackErrors { let g = csenv.g @@ -2312,15 +2325,18 @@ and CanMemberSigsMatchUpToCheck 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 + // - 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 (MustConvertTo(overallTy)) when isAppTy g overallTy && not (isSealedTy g overallTy) -> + let methodRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling + return! subsumeTypes overallTy methodRetTy | Some reqdRetTy -> let methodRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling - return! unifyTypes reqdRetTy methodRetTy + return! unifyTypes reqdRetTy.Commit methodRetTy | _ -> () } @@ -2523,7 +2539,7 @@ 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 = let g = csenv.g let amap = csenv.amap @@ -2597,7 +2613,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) @@ -2853,7 +2869,11 @@ and ResolveOverloading match reqdRetTyOpt with | None -> () | Some _ when calledMeth.Method.IsConstructor -> () + | Some (MustConvertTo(reqdRetTy)) when isAppTy g reqdRetTy && not (isSealedTy g reqdRetTy) -> + let actualRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling + return! TypesMustSubsumeOrConvertInsideUndo csenv ndeep trace cxsln m reqdRetTy actualRetTy | Some reqdRetTy -> + let reqdRetTy = reqdRetTy.Commit let actualRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling if isByrefTy g reqdRetTy then return! ErrorD(Error(FSComp.SR.tcByrefReturnImplicitlyDereferenced(), m)) diff --git a/src/fsharp/ConstraintSolver.fsi b/src/fsharp/ConstraintSolver.fsi index f2da70c8567..9c35b36edc4 100644 --- a/src/fsharp/ConstraintSolver.fsi +++ b/src/fsharp/ConstraintSolver.fsi @@ -107,6 +107,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 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 @@ -142,9 +153,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 From 265b14f985894e77218d40887dd4780d13b39324 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Fri, 15 Jan 2021 19:44:00 +0000 Subject: [PATCH 04/42] fix bug --- src/fsharp/CheckExpressions.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 14196bd129c..1044250017a 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -9653,7 +9653,7 @@ and TcAttribute canFail cenv (env: TcEnv) attrTgt (synAttr: SynAttribute) = 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] (MustEqual (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) From 28c2525904958e969e746546002f1c95295ffbbd Mon Sep 17 00:00:00 2001 From: Don Syme Date: Fri, 15 Jan 2021 21:18:45 +0000 Subject: [PATCH 05/42] assert constructor return type --- src/fsharp/CheckExpressions.fs | 2 +- src/fsharp/ConstraintSolver.fs | 4 ++-- src/fsharp/MethodCalls.fs | 7 +++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 1044250017a..2ba9dc0877c 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -8695,7 +8695,7 @@ and TcMethodApplication yield makeOneCalledMeth (minfo, pinfoOpt, false) ] let uniquelyResolved = - UnifyUniqueOverloading denv cenv.css mMethExpr callerArgCounts methodName ad preArgumentTypeCheckingCalledMethGroup returnTy + UnifyUniqueOverloading denv cenv.css mMethExpr callerArgCounts methodName ad preArgumentTypeCheckingCalledMethGroup returnTy uniquelyResolved, preArgumentTypeCheckingCalledMethGroup diff --git a/src/fsharp/ConstraintSolver.fs b/src/fsharp/ConstraintSolver.fs index 6d987bed4e5..665f72f903a 100644 --- a/src/fsharp/ConstraintSolver.fs +++ b/src/fsharp/ConstraintSolver.fs @@ -2330,7 +2330,7 @@ and CanMemberSigsMatchUpToCheck // -- 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 _ when ( (* minfo.IsConstructor || *) not alwaysCheckReturn && isNil unnamedCalledOutArgs) -> () | Some (MustConvertTo(overallTy)) when isAppTy g overallTy && not (isSealedTy g overallTy) -> let methodRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling return! subsumeTypes overallTy methodRetTy @@ -2868,7 +2868,7 @@ and ResolveOverloading // Unify return type match reqdRetTyOpt with | None -> () - | Some _ when calledMeth.Method.IsConstructor -> () + //| Some _ when calledMeth.Method.IsConstructor -> () | Some (MustConvertTo(reqdRetTy)) when isAppTy g reqdRetTy && not (isSealedTy g reqdRetTy) -> let actualRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling return! TypesMustSubsumeOrConvertInsideUndo csenv ndeep trace cxsln m reqdRetTy actualRetTy diff --git a/src/fsharp/MethodCalls.fs b/src/fsharp/MethodCalls.fs index 4fcdbea7618..e5c9e5b88be 100644 --- a/src/fsharp/MethodCalls.fs +++ b/src/fsharp/MethodCalls.fs @@ -359,7 +359,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) @@ -430,7 +430,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 @@ -511,8 +511,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 = From 5fcb36f96e906434e0c40f2eeda77fa04c6eee92 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Fri, 15 Jan 2021 21:42:08 +0000 Subject: [PATCH 06/42] no subsumption for type-directed records --- src/fsharp/CheckExpressions.fs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 2ba9dc0877c..2f4225bb058 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -5636,10 +5636,10 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = ) | SynExpr.Record (inherits, optOrigExpr, flds, mWholeExpr) -> - TcExprLeafProtect cenv overallTy env mWholeExpr (fun overallTy -> - CallExprHasTypeSink cenv.tcSink (mWholeExpr, env.NameEnv, overallTy, env.AccessRights) + //TcExprLeafProtect cenv overallTy env mWholeExpr (fun overallTy -> + CallExprHasTypeSink cenv.tcSink (mWholeExpr, env.NameEnv, overallTy.Commit, env.AccessRights) TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr) - ) + //) | SynExpr.While (spWhile, synGuardExpr, synBodyExpr, m) -> UnifyTypes cenv env m overallTy.Commit cenv.g.unit_ty @@ -6899,7 +6899,9 @@ and TcAssertExpr cenv overallTy env (m: range) tpenv x = TcExpr cenv overallTy env tpenv callDiagnosticsExpr -and TcRecdExpr cenv (overallTy: TType) env tpenv (inherits, optOrigExpr, flds, mWholeExpr) = +and TcRecdExpr cenv (overallTy: OverallTy) env tpenv (inherits, optOrigExpr, flds, mWholeExpr) = + + let overallTy = overallTy.Commit // Type directed resolution of record expressions means must subsume explicitly with upcast or box or :> let requiresCtor = (GetCtorShapeCounter env = 1) // Get special expression forms for constructors let haveCtor = Option.isSome inherits From b67d861705a445d7d6702a95dfb854a5974e79b6 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sat, 16 Jan 2021 16:02:16 +0000 Subject: [PATCH 07/42] fix bootstrap build --- src/fsharp/CheckExpressions.fs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 2f4225bb058..10e448472e7 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -6602,8 +6602,6 @@ and TcObjectExpr cenv (overallTy: TType) env tpenv (synObjTy, argopt, binds, ext let expr = mkCoerceIfNeeded cenv.g realObjTy objTy' expr expr, tpenv - - //------------------------------------------------------------------------- // TcConstStringExpr //------------------------------------------------------------------------- @@ -8901,13 +8899,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 = @@ -8923,9 +8921,12 @@ and TcMethodApplication let expr = mkLetsBind mMethExpr outArgTmpBinds expr expr, tyOfExpr cenv.g expr + // Subsumption to return type + let callExpr2b = mkCoerceIfNeeded cenv.g returnTy.Commit exprty callExpr2 + // Handle post-hoc property assignments let setterExprPrebinders, callExpr3 = - let expr = callExpr2 + let expr = callExpr2b if isCheckingAttributeCall then [], expr elif isNil finalAssignedItemSetters then @@ -8944,12 +8945,9 @@ and TcMethodApplication let expr = mkCompGenLet mMethExpr objv expr (mkCompGenSequential mMethExpr propSetExpr objExpr) setterExprPrebinders, expr - // Subsumption to return type - let callExpr3b = mkCoerceIfNeeded cenv.g returnTy.Commit exprty callExpr3 - // Build the lambda expression if any, if the method is used as a first-class value let callExpr4 = - let expr = callExpr3b + let expr = callExpr3 match lambdaVars with | None -> expr | Some curriedLambdaVars -> From 1a630b999eab510d589a7a665a2ec0733a6d92cf Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sat, 16 Jan 2021 16:23:27 +0000 Subject: [PATCH 08/42] fix test --- src/fsharp/CheckExpressions.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 10e448472e7..76ff3b351f6 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -465,9 +465,9 @@ let UnifyOverallType cenv (env: TcEnv) m overallTy actualTy = elif AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy actualTy then () else - UnifyTypes cenv env m actualTy overallTy + UnifyTypes cenv env m overallTy actualTy | _ -> - UnifyTypes cenv env m actualTy overallTy.Commit + UnifyTypes cenv env m overallTy.Commit actualTy let UnifyOverallTypeAndRecover cenv env m overallTy actualTy = try From 163e7071aed4c8b1c6ca624d41438125f802ea41 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 18 Jan 2021 13:00:00 +0000 Subject: [PATCH 09/42] fix test baselines --- tests/fsharp/typeProviders/negTests/neg1.bsl | 6 +++ tests/fsharp/typecheck/sigs/neg20.bsl | 43 +++----------------- tests/fsharp/typecheck/sigs/neg20.fs | 10 ++--- 3 files changed, 16 insertions(+), 43 deletions(-) diff --git a/tests/fsharp/typeProviders/negTests/neg1.bsl b/tests/fsharp/typeProviders/negTests/neg1.bsl index 8572d60442e..3710102af10 100644 --- a/tests/fsharp/typeProviders/negTests/neg1.bsl +++ b/tests/fsharp/typeProviders/negTests/neg1.bsl @@ -1638,16 +1638,22 @@ neg1.fsx(438,109,438,110): typecheck error FS0001: This expression was expected but here has type 'string' +neg1.fsx(438,9,438,111): typecheck error FS3033: The type provider 'Provider.GoodProviderForNegativeStaticParameterTypeTests' reported an error: Specified cast is not valid. + neg1.fsx(440,119,440,120): typecheck error FS0001: This expression was expected to have type 'int' but here has type 'string' +neg1.fsx(440,19,440,121): typecheck error FS3033: The type provider 'Provider.GoodProviderForNegativeStaticParameterTypeTests' reported an error: Specified cast is not valid. + neg1.fsx(440,119,440,120): typecheck error FS0001: This expression was expected to have type 'int' but here has type 'string' +neg1.fsx(440,19,440,121): typecheck error FS3033: The type provider 'Provider.GoodProviderForNegativeStaticParameterTypeTests' reported an error: Specified cast is not valid. + neg1.fsx(448,9,448,107): typecheck error FS3148: Too many static parameters. Expected at most 1 parameters, but got 2 unnamed and 0 named parameters. neg1.fsx(449,105,449,110): typecheck error FS3083: The static parameter 'Count' has already been given a value diff --git a/tests/fsharp/typecheck/sigs/neg20.bsl b/tests/fsharp/typecheck/sigs/neg20.bsl index 4227ab07193..729bfb2378e 100644 --- a/tests/fsharp/typecheck/sigs/neg20.bsl +++ b/tests/fsharp/typecheck/sigs/neg20.bsl @@ -49,11 +49,6 @@ neg20.fs(45,19,45,22): typecheck error FS0001: This expression was expected to h 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 @@ -69,17 +64,11 @@ 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(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(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(60,26,60,33): typecheck error FS0001: The type 'A' is not compatible with the 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(61,27,61,35): typecheck error FS0001: The type 'B2' is not compatible with the type 'B1' -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(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(62,26,62,33): typecheck error FS0001: The type 'B' is not compatible with the type 'C' neg20.fs(71,34,71,42): typecheck error FS0001: Type mismatch. Expecting a 'A list' @@ -87,11 +76,6 @@ 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 @@ -110,26 +94,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(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(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(96,26,96,33): typecheck error FS0001: The type 'A' is not compatible with the 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: The type 'A' is not compatible with the type 'B' neg20.fs(108,12,108,16): typecheck error FS0001: Type mismatch. Expecting a 'B * B -> 'a' diff --git a/tests/fsharp/typecheck/sigs/neg20.fs b/tests/fsharp/typecheck/sigs/neg20.fs index 5d465aeea93..9392c407127 100644 --- a/tests/fsharp/typecheck/sigs/neg20.fs +++ b/tests/fsharp/typecheck/sigs/neg20.fs @@ -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 = From 3eea4d58cda7e60ab7c6ee303fa563c9390c9530 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 18 Jan 2021 13:20:44 +0000 Subject: [PATCH 10/42] respect rigid type annotations within expressions --- src/fsharp/CheckExpressions.fs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 76ff3b351f6..e6cedd99c24 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -5283,7 +5283,7 @@ and TcExprFlex cenv flex compat (desiredTy: TType) (env: TcEnv) tpenv (e: SynExp if compat then (destTyparTy cenv.g argty).SetIsCompatFlex(true) AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css e.Range NoTrace desiredTy argty - let e', tpenv = TcExpr cenv (MustEqual argty) env tpenv e + let e', tpenv = TcExpr cenv (MustConvertTo argty) env tpenv e let e' = mkCoerceIfNeeded cenv.g desiredTy argty e' e', tpenv else @@ -5521,7 +5521,7 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = | SynExpr.Typed (synBodyExpr, synType, m) -> let tgtTy, tpenv = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synType UnifyTypes cenv env m overallTy.Commit tgtTy - let expr, tpenv = TcExpr cenv (MustConvertTo tgtTy) env tpenv synBodyExpr + let expr, tpenv = TcExpr cenv (MustEqual tgtTy) env tpenv synBodyExpr expr, tpenv // e :? ty @@ -5578,7 +5578,7 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = | SynExpr.Lazy (synInnerExpr, m) -> let innerTy = NewInferenceType () UnifyTypes cenv env m overallTy.Commit (mkLazyTy cenv.g innerTy) - let innerExpr, tpenv = TcExpr cenv (MustConvertTo innerTy) env tpenv synInnerExpr + let innerExpr, tpenv = TcExpr cenv (MustEqual innerTy) env tpenv synInnerExpr let expr = mkLazyDelayed cenv.g m innerTy (mkUnitDelayLambda cenv.g m innerExpr) expr, tpenv From 874f8a4ac364f4fb5d57f17c7ce83b5e350e5285 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 18 Jan 2021 15:27:03 +0000 Subject: [PATCH 11/42] respect rigid type annotations within expressions --- src/fsharp/CheckExpressions.fs | 48 ++++++++++++------- src/fsharp/FSComp.txt | 1 + src/fsharp/LanguageFeatures.fs | 3 ++ src/fsharp/LanguageFeatures.fsi | 1 + src/fsharp/SyntaxTree.fs | 1 + src/fsharp/SyntaxTreeOps.fs | 7 +-- src/fsharp/pars.fsy | 2 +- src/fsharp/service/ServiceAssemblyContent.fs | 2 +- .../service/ServiceInterfaceStubGenerator.fs | 2 +- src/fsharp/service/ServiceNavigation.fs | 2 +- src/fsharp/service/ServiceParseTreeWalk.fs | 2 +- src/fsharp/service/ServiceStructure.fs | 2 +- src/fsharp/service/ServiceUntypedParse.fs | 4 +- src/fsharp/xlf/FSComp.txt.cs.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.de.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.es.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.fr.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.it.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.ja.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.ko.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.pl.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.pt-BR.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.ru.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.tr.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.zh-Hans.xlf | 5 ++ src/fsharp/xlf/FSComp.txt.zh-Hant.xlf | 5 ++ .../SurfaceArea.netstandard.fs | 2 + tests/fsharp/typecheck/sigs/neg20.bsl | 20 -------- tests/fsharp/typecheck/sigs/neg20.fs | 4 +- tests/service/ServiceUntypedParseTests.fs | 2 +- 30 files changed, 118 insertions(+), 52 deletions(-) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index e6cedd99c24..5011cac1746 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -4932,7 +4932,7 @@ and TcPat warnOnUpper cenv env topValInfo vFlags (tpenv, names, takenNames) ty p | SynPat.FromParseError(p, _) -> convSynPatToSynExpr p | SynPat.Const (c, m) -> SynExpr.Const (c, m) | SynPat.Named (SynPat.Wild _, id, _, None, _) -> SynExpr.Ident id - | SynPat.Typed (p, cty, m) -> SynExpr.Typed (convSynPatToSynExpr p, cty, m) + | SynPat.Typed (p, cty, m) -> SynExpr.Typed (convSynPatToSynExpr p, cty, false, m) | SynPat.LongIdent (LongIdentWithDots(longId, dotms) as lidwd, _, _tyargs, args, None, m) -> let args = match args with SynArgPats.Pats args -> args | _ -> failwith "impossible: active patterns can be used only with SynConstructorArgs.Pats" let e = @@ -5278,16 +5278,21 @@ and TcExprOfUnknownType cenv env tpenv expr = expr', exprty, tpenv and TcExprFlex cenv flex compat (desiredTy: TType) (env: TcEnv) tpenv (e: 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 desiredTy argty - let e', tpenv = TcExpr cenv (MustConvertTo argty) env tpenv e + let e', tpenv = TcExprFlex2 cenv argty env tpenv e let e' = mkCoerceIfNeeded cenv.g desiredTy argty e' e', tpenv else - TcExpr cenv (MustConvertTo desiredTy) env tpenv e + TcExprFlex2 cenv desiredTy env tpenv e + +and TcExprFlex2 cenv desiredTy env tpenv e = + TcExpr cenv (MustConvertTo desiredTy) env tpenv e and TcExpr cenv ty (env: TcEnv) tpenv (expr: SynExpr) = // Start an error recovery handler @@ -5476,10 +5481,8 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = ) | SynExpr.Const (synConst, m) -> - TcExprLeafProtect cenv overallTy env m (fun overallTy -> - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights) - TcConstExpr cenv overallTy env m tpenv synConst - ) + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) + TcConstExpr cenv overallTy env m tpenv synConst | SynExpr.Lambda _ -> TcIteratedLambdas cenv true env overallTy Set.empty tpenv synExpr @@ -5518,10 +5521,17 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = error(Error(FSComp.SR.tcFixedNotAllowed(), m)) // e: ty - | SynExpr.Typed (synBodyExpr, synType, m) -> + | SynExpr.Typed (synBodyExpr, synType, isFromReturnAnnotation, m) -> let tgtTy, tpenv = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synType - UnifyTypes cenv env m overallTy.Commit tgtTy - let expr, tpenv = TcExpr cenv (MustEqual tgtTy) env tpenv synBodyExpr + UnifyOverallType cenv env m overallTy tgtTy + // Type annotations stemming from binding/return position allow conversion, e.g. + // let _ : obj = 1 + // Type annotations stemming from expression annotations are rigid, e.g. this is + // not allowed: + // (1 : obj) + let overallTyInner = if isFromReturnAnnotation then MustConvertTo tgtTy else MustEqual tgtTy + let expr, tpenv = TcExpr cenv overallTyInner env tpenv synBodyExpr + let expr = mkCoerceIfNeeded cenv.g overallTy.Commit overallTyInner.Commit expr expr, tpenv // e :? ty @@ -6836,15 +6846,17 @@ and TcInterpolatedStringExpr cenv (overallTy: TType) env m tpenv (parts: SynInte //------------------------------------------------------------------------- /// Check a constant expression. -and TcConstExpr cenv (overallTy: TType) 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) -> + TcExprLeafProtect cenv overallTy env m <| fun overallTy -> UnifyTypes cenv env m overallTy (mkByteArrayTy cenv.g) Expr.Op (TOp.Bytes bytes, [], [], m), tpenv | SynConst.UInt16s arr -> + TcExprLeafProtect cenv overallTy env m <| fun overallTy -> UnifyTypes cenv env m overallTy (mkArrayType cenv.g cenv.g.uint16_ty); Expr.Op (TOp.UInt16s arr, [], [], m), tpenv | SynConst.UserNum (s, suffix) -> @@ -6873,13 +6885,14 @@ and TcConstExpr cenv (overallTy: TType) env m tpenv c = else match ccuOfTyconRef mref with | Some ccu when ccuEq ccu cenv.g.fslibCcu -> - SynExpr.Typed (expr, SynType.LongIdent(LongIdentWithDots(pathToSynLid m ["System";"Numerics";"BigInteger"], [])), m) + SynExpr.Typed (expr, SynType.LongIdent(LongIdentWithDots(pathToSynLid m ["System";"Numerics";"BigInteger"], [])), false, m) | _ -> expr - TcExpr cenv (MustEqual overallTy) env tpenv expr + TcExpr cenv overallTy env tpenv expr | _ -> + TcExprLeafProtect cenv overallTy env m <| fun overallTy -> let c' = TcConst cenv overallTy m env c Expr.Const (c', m, overallTy), tpenv @@ -6896,7 +6909,6 @@ and TcAssertExpr cenv overallTy env (m: range) tpenv x = TcExpr cenv overallTy env tpenv callDiagnosticsExpr - and TcRecdExpr cenv (overallTy: OverallTy) env tpenv (inherits, optOrigExpr, flds, mWholeExpr) = let overallTy = overallTy.Commit // Type directed resolution of record expressions means must subsume explicitly with upcast or box or :> @@ -7530,7 +7542,7 @@ 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 -> + | SynExpr.Typed (synBodyExpr, synType, _, _m) when delayed.IsEmpty && overallTyOpt.IsNone -> let tgtTy, _tpenv = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synType check (Some (MustEqual tgtTy)) resultOpt synBodyExpr delayed @@ -7574,7 +7586,7 @@ and TcFunctionApplicationThen cenv (overallTy: OverallTy) env tpenv mExprAndArg | _ -> false) | _ -> () - let arg, tpenv = TcExpr cenv (MustEqual domainTy) env tpenv synArg + let arg, tpenv = TcExprFlex2 cenv domainTy env tpenv synArg let exprAndArg, resultTy = buildApp cenv expr resultTy arg mExprAndArg TcDelayed cenv overallTy env tpenv mExprAndArg exprAndArg resultTy atomicFlag delayed @@ -7931,7 +7943,7 @@ and TcItemThen cenv (overallTy: OverallTy) env tpenv (tinstEnclosing, item, mIte match e with | SynExpr.New (_, _, synExpr, _) | SynExpr.Paren (synExpr, _, _, _) - | SynExpr.Typed (synExpr, _, _) + | SynExpr.Typed (synExpr, _, _, _) | SynExpr.TypeApp (synExpr, _, _, _, _, _, _) | SynExpr.TypeTest (synExpr, _, _) | SynExpr.Upcast (synExpr, _, _) @@ -9080,7 +9092,7 @@ and TcMethodArg cenv env (lambdaPropagationInfo, tpenv) (lambdaPropagationInfoFo | _ -> () loop argTy 0 - let e', tpenv = TcExpr cenv (MustEqual argTy) env tpenv argExpr + let e', tpenv = TcExprFlex2 cenv argTy env tpenv argExpr // After we have checked, propagate the info from argument into the overloads that receive it. // diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 35001aedfed..54837b8751e 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1521,6 +1521,7 @@ featureNullableOptionalInterop,"nullable optional interop" featureDefaultInterfaceMemberConsumption,"default interface member consumption" featureStringInterpolation,"string interpolation" featureWitnessPassing,"witness passing for trait constraints in F# quotations" +featureImplicitConversion,"implicit upcasts and other conversions for function returns, bindings and other expressions" 3353,fsiInvalidDirective,"Invalid directive '#%s %s'" 3360,typrelInterfaceWithConcreteAndVariable,"'%s' cannot implement the interface '%s' with the two instantiations '%s' and '%s' because they may unify." 3361,typrelInterfaceWithConcreteAndVariableObjectExpression,"You cannot implement the interface '%s' with the two instantiations '%s' and '%s' because they may unify." diff --git a/src/fsharp/LanguageFeatures.fs b/src/fsharp/LanguageFeatures.fs index 96c4f6baa5c..54ce4055e7f 100644 --- a/src/fsharp/LanguageFeatures.fs +++ b/src/fsharp/LanguageFeatures.fs @@ -32,6 +32,7 @@ type LanguageFeature = | NullableOptionalInterop | DefaultInterfaceMemberConsumption | WitnessPassing + | ImplicitConversion | InterfacesWithMultipleGenericInstantiation | StringInterpolation | OverloadsForCustomOperations @@ -74,6 +75,7 @@ type LanguageVersion (specifiedVersionAsString) = LanguageFeature.StringInterpolation, languageVersion50 // F# preview + LanguageFeature.ImplicitConversion, previewVersion LanguageFeature.OverloadsForCustomOperations, previewVersion LanguageFeature.ExpandedMeasurables, previewVersion LanguageFeature.FromEndSlicing, previewVersion @@ -146,6 +148,7 @@ type LanguageVersion (specifiedVersionAsString) = | LanguageFeature.NullableOptionalInterop -> FSComp.SR.featureNullableOptionalInterop() | LanguageFeature.DefaultInterfaceMemberConsumption -> FSComp.SR.featureDefaultInterfaceMemberConsumption() | LanguageFeature.WitnessPassing -> FSComp.SR.featureWitnessPassing() + | LanguageFeature.ImplicitConversion -> FSComp.SR.featureImplicitConversion() | 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 b914016d9a5..883f5cf6e8f 100644 --- a/src/fsharp/LanguageFeatures.fsi +++ b/src/fsharp/LanguageFeatures.fsi @@ -20,6 +20,7 @@ type LanguageFeature = | NullableOptionalInterop | DefaultInterfaceMemberConsumption | WitnessPassing + | ImplicitConversion | InterfacesWithMultipleGenericInstantiation | StringInterpolation | OverloadsForCustomOperations diff --git a/src/fsharp/SyntaxTree.fs b/src/fsharp/SyntaxTree.fs index 6e9b68280c6..568cde006d5 100644 --- a/src/fsharp/SyntaxTree.fs +++ b/src/fsharp/SyntaxTree.fs @@ -573,6 +573,7 @@ type SynExpr = | Typed of expr: SynExpr * targetType: SynType * + isFromReturnAnnotation: bool * range: range /// F# syntax: e1, ..., eN diff --git a/src/fsharp/SyntaxTreeOps.fs b/src/fsharp/SyntaxTreeOps.fs index 3fd1ce32224..c225b139808 100644 --- a/src/fsharp/SyntaxTreeOps.fs +++ b/src/fsharp/SyntaxTreeOps.fs @@ -97,7 +97,7 @@ let rec IsControlFlowExpression e = | SynExpr.For _ | SynExpr.ForEach _ | SynExpr.While _ -> true - | SynExpr.Typed (e, _, _) -> IsControlFlowExpression e + | SynExpr.Typed (e, _, _, _) -> IsControlFlowExpression e | _ -> false let mkAnonField (ty: SynType) = Field([], false, None, ty, false, PreXmlDoc.Empty, None, ty.Range) @@ -554,7 +554,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, true, rhsExpr.Range), Some(SynBindingReturnInfo(ty, tym, rAttribs) ) | None -> rhsExpr, None rhsExpr, retTyOpt @@ -641,7 +642,7 @@ let rec synExprContainsError inpExpr = | SynExpr.AddressOf (_, e, _, _) | SynExpr.CompExpr (_, _, e, _) | SynExpr.ArrayOrListOfSeqExpr (_, e, _) - | SynExpr.Typed (e, _, _) + | SynExpr.Typed (e, _, _, _) | SynExpr.FromParseError (e, _) | SynExpr.Do (e, _) | SynExpr.Assert (e, _) diff --git a/src/fsharp/pars.fsy b/src/fsharp/pars.fsy index cfce563057b..a00c45c9274 100644 --- a/src/fsharp/pars.fsy +++ b/src/fsharp/pars.fsy @@ -3298,7 +3298,7 @@ typedSeqExprBlockR: typedSeqExpr: | seqExpr COLON typeWithTypeConstraints - { SynExpr.Typed ($1, $3, unionRanges $1.Range $3.Range) } + { SynExpr.Typed ($1, $3, false, unionRanges $1.Range $3.Range) } | seqExpr { $1 } diff --git a/src/fsharp/service/ServiceAssemblyContent.fs b/src/fsharp/service/ServiceAssemblyContent.fs index 69865f77f40..19d32a754bd 100644 --- a/src/fsharp/service/ServiceAssemblyContent.fs +++ b/src/fsharp/service/ServiceAssemblyContent.fs @@ -555,7 +555,7 @@ module ParsedInput = and walkExpr = function | SynExpr.Paren (e, _, _, _) | SynExpr.Quote (_, _, e, _, _) - | SynExpr.Typed (e, _, _) + | SynExpr.Typed (e, _, _, _) | SynExpr.InferredUpcast (e, _) | SynExpr.InferredDowncast (e, _) | SynExpr.AddressOf (_, e, _, _) diff --git a/src/fsharp/service/ServiceInterfaceStubGenerator.fs b/src/fsharp/service/ServiceInterfaceStubGenerator.fs index 278f31019f4..b78a1e27b40 100644 --- a/src/fsharp/service/ServiceInterfaceStubGenerator.fs +++ b/src/fsharp/service/ServiceInterfaceStubGenerator.fs @@ -764,7 +764,7 @@ module InterfaceStubGenerator = | SynExpr.Paren (synExpr, _, _, _parenRange) -> walkExpr synExpr - | SynExpr.Typed (synExpr, _synType, _range) -> + | SynExpr.Typed (synExpr, _synType, _, _range) -> walkExpr synExpr | SynExpr.Tuple (_, synExprList, _, _range) diff --git a/src/fsharp/service/ServiceNavigation.fs b/src/fsharp/service/ServiceNavigation.fs index 06165e3220b..6483fcf04c0 100755 --- a/src/fsharp/service/ServiceNavigation.fs +++ b/src/fsharp/service/ServiceNavigation.fs @@ -136,7 +136,7 @@ module NavigationImpl = let processBinding isMember enclosingEntityKind isAbstract (Binding(_, _, _, _, _, _, SynValData(memberOpt, _, _), synPat, _, synExpr, _, _)) = let m = match synExpr with - | SynExpr.Typed (e, _, _) -> e.Range // fix range for properties with type annotations + | SynExpr.Typed (e, _, _, _) -> e.Range // fix range for properties with type annotations | _ -> synExpr.Range match synPat, memberOpt with diff --git a/src/fsharp/service/ServiceParseTreeWalk.fs b/src/fsharp/service/ServiceParseTreeWalk.fs index e7748415c3c..4bdd61a9ea9 100755 --- a/src/fsharp/service/ServiceParseTreeWalk.fs +++ b/src/fsharp/service/ServiceParseTreeWalk.fs @@ -222,7 +222,7 @@ module public AstTraversal = yield dive fillExpr fillExpr.Range traverseSynExpr ] |> pick expr - | SynExpr.Typed (synExpr, synType, _range) -> + | SynExpr.Typed (synExpr, synType, _, _range) -> [ traverseSynExpr synExpr; traverseSynType synType ] |> List.tryPick id | SynExpr.Tuple (_, synExprList, _, _range) diff --git a/src/fsharp/service/ServiceStructure.fs b/src/fsharp/service/ServiceStructure.fs index 9294d1b609f..9e1580a3878 100644 --- a/src/fsharp/service/ServiceStructure.fs +++ b/src/fsharp/service/ServiceStructure.fs @@ -230,7 +230,7 @@ module Structure = | SynExpr.InferredUpcast (e, _) | SynExpr.DotGet (e, _, _, _) | SynExpr.Do (e, _) - | SynExpr.Typed (e, _, _) + | SynExpr.Typed (e, _, _, _) | SynExpr.DotIndexedGet (e, _, _, _) -> parseExpr e | SynExpr.Set (e1, e2, _) diff --git a/src/fsharp/service/ServiceUntypedParse.fs b/src/fsharp/service/ServiceUntypedParse.fs index 9a9d83f059a..d83e04a7323 100755 --- a/src/fsharp/service/ServiceUntypedParse.fs +++ b/src/fsharp/service/ServiceUntypedParse.fs @@ -426,7 +426,7 @@ type FSharpParseFileResults(errors: FSharpDiagnostic[], input: ParsedInput optio | SynExpr.AddressOf (_, e, _, _) | SynExpr.CompExpr (_, _, e, _) | SynExpr.ArrayOrListOfSeqExpr (_, e, _) - | SynExpr.Typed (e, _, _) + | SynExpr.Typed (e, _, _, _) | SynExpr.FromParseError (e, _) | SynExpr.DiscardAfterMissingQualificationAfterDot (e, _) | SynExpr.Do (e, _) @@ -1073,7 +1073,7 @@ module UntypedParseImpl = | _ -> None | SynExpr.Paren (e, _, _, _) -> walkExprWithKind parentKind e | SynExpr.Quote (_, _, e, _, _) -> walkExprWithKind parentKind e - | SynExpr.Typed (e, _, _) -> walkExprWithKind parentKind e + | SynExpr.Typed (e, _, _, _) -> walkExprWithKind parentKind e | SynExpr.Tuple (_, es, _, _) -> List.tryPick (walkExprWithKind parentKind) es | SynExpr.ArrayOrList (_, es, _) -> List.tryPick (walkExprWithKind parentKind) es | SynExpr.Record (_, _, fields, r) -> diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index 8f7a4d14aec..aefc534fb84 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -107,6 +107,11 @@ řez od konce + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + implicit yield implicitní yield diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index a8c417263bd..5f97c380a00 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -107,6 +107,11 @@ Segmentierung ab Ende + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + implicit yield implizite yield-Anweisung diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index dc47df31a62..e7bc48797fe 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -107,6 +107,11 @@ segmentación desde el final + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + implicit yield elemento yield implícito diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index 3b599054f30..fc6e721dd75 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -107,6 +107,11 @@ découpage depuis la fin + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + implicit yield yield implicite diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index dc0ce43fb96..1bb64339ba4 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -107,6 +107,11 @@ sezionamento dalla fine + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + implicit yield istruzione yield implicita diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index 33ebfc8a8c9..a280cec07e9 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -107,6 +107,11 @@ 開始と終了を指定したスライス + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + implicit yield 暗黙的な yield diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index fa785905abe..2d4186317b9 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -107,6 +107,11 @@ 끝에서부터 조각화 + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + implicit yield 암시적 yield diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index b05e1828865..13bb0af4bb7 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -107,6 +107,11 @@ wycinanie od końca + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + implicit yield niejawne słowo kluczowe yield diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index e5ba857f12b..958dab0dc8c 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -107,6 +107,11 @@ divisão começando no final + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + implicit yield yield implícito diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index 41ad0bd5180..ba2871ca7da 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -107,6 +107,11 @@ срезы от конца + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + implicit yield неявное использование yield diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index c00c6ac6b6f..eec54a3f233 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -107,6 +107,11 @@ uçtan dilimleme + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + implicit yield örtük yield diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index d725c4cca05..23d95c576c3 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -107,6 +107,11 @@ 从端切片 + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + implicit yield 隐式 yield diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index 4766d46bee5..6e31af6d1f8 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -107,6 +107,11 @@ 從尾端切割 + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + implicit yield 隱含 yield diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs index 20a1eab5459..f33645d96c4 100644 --- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs +++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs @@ -7336,6 +7336,8 @@ FSharp.Compiler.SyntaxTree+SynExpr+Typed: SynExpr expr FSharp.Compiler.SyntaxTree+SynExpr+Typed: SynExpr get_expr() FSharp.Compiler.SyntaxTree+SynExpr+Typed: SynType get_targetType() FSharp.Compiler.SyntaxTree+SynExpr+Typed: SynType targetType +FSharp.Compiler.SyntaxTree+SynExpr+Typed: Boolean get_isFromReturnAnnotation() +FSharp.Compiler.SyntaxTree+SynExpr+Typed: Boolean isFromReturnAnnotation FSharp.Compiler.SyntaxTree+SynExpr+Upcast: FSharp.Compiler.Text.Range get_range() FSharp.Compiler.SyntaxTree+SynExpr+Upcast: FSharp.Compiler.Text.Range range FSharp.Compiler.SyntaxTree+SynExpr+Upcast: SynExpr expr diff --git a/tests/fsharp/typecheck/sigs/neg20.bsl b/tests/fsharp/typecheck/sigs/neg20.bsl index 729bfb2378e..a6a3aadc4b7 100644 --- a/tests/fsharp/typecheck/sigs/neg20.bsl +++ b/tests/fsharp/typecheck/sigs/neg20.bsl @@ -19,11 +19,6 @@ neg20.fs(32,32,32,35): typecheck error FS0001: This expression was expected to h 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 @@ -54,16 +49,6 @@ neg20.fs(48,11,48,14): typecheck error FS0001: This expression was expected to h 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: The type 'A' is not compatible with the type 'B' neg20.fs(61,27,61,35): typecheck error FS0001: The type 'B2' is not compatible with the type 'B1' @@ -121,11 +106,6 @@ neg20.fs(128,19,128,22): typecheck error FS0001: This expression was expected to 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 diff --git a/tests/fsharp/typecheck/sigs/neg20.fs b/tests/fsharp/typecheck/sigs/neg20.fs index 9392c407127..1574d4d3340 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! @@ -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 diff --git a/tests/service/ServiceUntypedParseTests.fs b/tests/service/ServiceUntypedParseTests.fs index 3c87e8f7973..c9edab7d3f9 100644 --- a/tests/service/ServiceUntypedParseTests.fs +++ b/tests/service/ServiceUntypedParseTests.fs @@ -184,7 +184,7 @@ let ``SynType.Paren ranges`` () = let (SynModuleOrNamespace (decls = decls)) = parseSourceCodeAndGetModule source decls |> List.map (fun decl -> match decl with - | SynModuleDecl.DoExpr (expr = SynExpr.Paren (expr = SynExpr.Typed (_, synType ,_))) -> + | SynModuleDecl.DoExpr (expr = SynExpr.Paren (expr = SynExpr.Typed (_, synType, _, _))) -> getParenTypes synType |> List.map (fun synType -> getRangeCoords synType.Range) | _ -> failwith "Could not get binding") From b34e4dede82be43fff701c22fa277e19bfc4124b Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 18 Jan 2021 15:50:14 +0000 Subject: [PATCH 12/42] reenable rigid type annotations within expressions --- src/fsharp/CheckExpressions.fs | 15 ++++++++------- .../E_rigidtypeannotation02.fs | 11 ----------- .../E_rigidtypeannotation02b.fs | 8 -------- .../Expressions/Type-relatedExpressions/env.lst | 2 -- .../ConstraintSolving/E_NoImplicitDowncast01.fs | 14 -------------- .../InferenceProcedures/ConstraintSolving/env.lst | 2 -- 6 files changed, 8 insertions(+), 44 deletions(-) delete mode 100644 tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/E_rigidtypeannotation02.fs delete mode 100644 tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/E_rigidtypeannotation02b.fs delete mode 100644 tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/E_NoImplicitDowncast01.fs diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 5011cac1746..1896496747a 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -5521,15 +5521,16 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = error(Error(FSComp.SR.tcFixedNotAllowed(), m)) // e: ty - | SynExpr.Typed (synBodyExpr, synType, isFromReturnAnnotation, m) -> + | SynExpr.Typed (synBodyExpr, synType, _isFromReturnAnnotation, m) -> let tgtTy, tpenv = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synType UnifyOverallType cenv env m overallTy tgtTy - // Type annotations stemming from binding/return position allow conversion, e.g. - // let _ : obj = 1 - // Type annotations stemming from expression annotations are rigid, e.g. this is - // not allowed: - // (1 : obj) - let overallTyInner = if isFromReturnAnnotation then MustConvertTo tgtTy else MustEqual tgtTy + // Possible rule (not currently activated): + // Type annotations stemming from binding/return position allow conversion, e.g. + // let _ : obj = 1 + // Type annotations stemming from expression annotations are rigid, e.g. this is + // not allowed: + // (1 : obj) + let overallTyInner = (* if isFromReturnAnnotation then *) MustConvertTo tgtTy (* else MustEqual tgtTy *) let expr, tpenv = TcExpr cenv overallTyInner env tpenv synBodyExpr let expr = mkCoerceIfNeeded cenv.g overallTy.Commit overallTyInner.Commit expr expr, tpenv 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 From 266e9a10ddabc807aec0ccceee20fd06ec256285 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 18 Jan 2021 16:12:40 +0000 Subject: [PATCH 13/42] update baseline --- tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs index f33645d96c4..f9beaa8e1be 100644 --- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs +++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs @@ -7622,7 +7622,7 @@ FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewTryWith(SynExpr, FSharp.Compiler. FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewTuple(Boolean, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.SyntaxTree+SynExpr], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Text.Range], FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewTypeApp(SynExpr, FSharp.Compiler.Text.Range, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.SyntaxTree+SynType], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Text.Range], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range], FSharp.Compiler.Text.Range, FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewTypeTest(SynExpr, SynType, FSharp.Compiler.Text.Range) -FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewTyped(SynExpr, SynType, FSharp.Compiler.Text.Range) +FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewTyped(SynExpr, SynType, Boolean, FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewUpcast(SynExpr, SynType, FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewWhile(DebugPointAtWhile, SynExpr, SynExpr, FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTree+SynExpr: SynExpr NewYieldOrReturn(System.Tuple`2[System.Boolean,System.Boolean], SynExpr, FSharp.Compiler.Text.Range) From 99aa42ddb1799bfc7fbc59faa6032599a8cd52a3 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 19 Jan 2021 13:50:20 +0000 Subject: [PATCH 14/42] add language version check --- src/fsharp/CheckExpressions.fs | 10 +- src/fsharp/ConstraintSolver.fs | 5 +- tests/fsharp/tests.fs | 20 +- tests/fsharp/typeProviders/negTests/neg1.bsl | 6 - tests/fsharp/typecheck/sigs/neg24.bsl | 40 ++ tests/fsharp/typecheck/sigs/neg24.fs | 339 +++++++++++++ .../fsharp/typecheck/sigs/version50/neg20.bsl | 417 ++++++++++++++++ .../fsharp/typecheck/sigs/version50/neg20.fs | 445 ++++++++++++++++++ 8 files changed, 1265 insertions(+), 17 deletions(-) create mode 100644 tests/fsharp/typecheck/sigs/neg24.bsl create mode 100644 tests/fsharp/typecheck/sigs/neg24.fs create mode 100644 tests/fsharp/typecheck/sigs/version50/neg20.bsl create mode 100644 tests/fsharp/typecheck/sigs/version50/neg20.fs diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 1896496747a..defaeb19326 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -457,7 +457,7 @@ let UnifyTypes cenv (env: TcEnv) m actualTy expectedTy = // then allow subsumption. let UnifyOverallType cenv (env: TcEnv) m overallTy actualTy = match overallTy with - | MustConvertTo(overallTy) when isAppTy cenv.g overallTy && not (isSealedTy cenv.g overallTy) -> + | MustConvertTo(overallTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion && not (isSealedTy cenv.g overallTy) -> let actualTy = tryNormalizeMeasureInType cenv.g actualTy let overallTy = tryNormalizeMeasureInType cenv.g overallTy if AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy actualTy then @@ -5440,7 +5440,7 @@ and TcExprUndelayedNoType cenv env tpenv synExpr: Expr * TType * _ = and TcExprLeafProtectExcept p cenv (overallTy: OverallTy) (env: TcEnv) m f = match overallTy with - | MustConvertTo(oty) when not (p oty) && isAppTy cenv.g oty && not (isSealedTy cenv.g oty) -> + | MustConvertTo(oty) when cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion && not (p oty) && not (isSealedTy cenv.g oty) -> let oty2 = NewInferenceType() AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace oty oty2 let expr, tpenv = f oty2 @@ -5531,9 +5531,9 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = // not allowed: // (1 : obj) let overallTyInner = (* if isFromReturnAnnotation then *) MustConvertTo tgtTy (* else MustEqual tgtTy *) - let expr, tpenv = TcExpr cenv overallTyInner env tpenv synBodyExpr - let expr = mkCoerceIfNeeded cenv.g overallTy.Commit overallTyInner.Commit expr - expr, tpenv + let bodyExpr, tpenv = TcExpr cenv overallTyInner env tpenv synBodyExpr + let bodyExpr = mkCoerceIfNeeded cenv.g overallTy.Commit overallTyInner.Commit bodyExpr + bodyExpr, tpenv // e :? ty | SynExpr.TypeTest (synInnerExpr, tgtTy, m) -> diff --git a/src/fsharp/ConstraintSolver.fs b/src/fsharp/ConstraintSolver.fs index 665f72f903a..c8951b6ecf5 100644 --- a/src/fsharp/ConstraintSolver.fs +++ b/src/fsharp/ConstraintSolver.fs @@ -2331,7 +2331,7 @@ and CanMemberSigsMatchUpToCheck // - Never take into account return type information for constructors match reqdRetTyOpt with | Some _ when ( (* minfo.IsConstructor || *) not alwaysCheckReturn && isNil unnamedCalledOutArgs) -> () - | Some (MustConvertTo(overallTy)) when isAppTy g overallTy && not (isSealedTy g overallTy) -> + | Some (MustConvertTo(overallTy)) when g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion && not (isSealedTy g overallTy) -> let methodRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling return! subsumeTypes overallTy methodRetTy | Some reqdRetTy -> @@ -2868,8 +2868,7 @@ and ResolveOverloading // Unify return type match reqdRetTyOpt with | None -> () - //| Some _ when calledMeth.Method.IsConstructor -> () - | Some (MustConvertTo(reqdRetTy)) when isAppTy g reqdRetTy && not (isSealedTy g reqdRetTy) -> + | Some (MustConvertTo(reqdRetTy)) when g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion && not (isSealedTy g reqdRetTy) -> let actualRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling return! TypesMustSubsumeOrConvertInsideUndo csenv ndeep trace cxsln m reqdRetTy actualRetTy | Some reqdRetTy -> diff --git a/tests/fsharp/tests.fs b/tests/fsharp/tests.fs index 5de0936fdab..fbe6c29f6cc 100644 --- a/tests/fsharp/tests.fs +++ b/tests/fsharp/tests.fs @@ -2465,7 +2465,14 @@ module TypecheckTests = let ``type check neg19`` () = singleNegTest (testConfig' "typecheck/sigs") "neg19" [] - 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 neg20 version preview`` () = + let cfg = testConfig' "typecheck/sigs" + singleVersionedNegTest cfg "preview" "neg20" [] let ``type check neg21`` () = singleNegTest (testConfig' "typecheck/sigs") "neg21" @@ -2477,17 +2484,24 @@ module TypecheckTests = let ``type check neg23`` () = singleNegTest (testConfig' "typecheck/sigs") "neg23" [] - let ``type check neg24 version 4.6`` () = + let ``type check neg24 version 4_6`` () = let cfg = testConfig' "typecheck/sigs/version46" // 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.6" "neg24" [] - let ``type check neg24 version 4.7`` () = + let ``type check neg24 version 4_7`` () = 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/typeProviders/negTests/neg1.bsl b/tests/fsharp/typeProviders/negTests/neg1.bsl index 3710102af10..8572d60442e 100644 --- a/tests/fsharp/typeProviders/negTests/neg1.bsl +++ b/tests/fsharp/typeProviders/negTests/neg1.bsl @@ -1638,22 +1638,16 @@ neg1.fsx(438,109,438,110): typecheck error FS0001: This expression was expected but here has type 'string' -neg1.fsx(438,9,438,111): typecheck error FS3033: The type provider 'Provider.GoodProviderForNegativeStaticParameterTypeTests' reported an error: Specified cast is not valid. - neg1.fsx(440,119,440,120): typecheck error FS0001: This expression was expected to have type 'int' but here has type 'string' -neg1.fsx(440,19,440,121): typecheck error FS3033: The type provider 'Provider.GoodProviderForNegativeStaticParameterTypeTests' reported an error: Specified cast is not valid. - neg1.fsx(440,119,440,120): typecheck error FS0001: This expression was expected to have type 'int' but here has type 'string' -neg1.fsx(440,19,440,121): typecheck error FS3033: The type provider 'Provider.GoodProviderForNegativeStaticParameterTypeTests' reported an error: Specified cast is not valid. - neg1.fsx(448,9,448,107): typecheck error FS3148: Too many static parameters. Expected at most 1 parameters, but got 2 unnamed and 0 named parameters. neg1.fsx(449,105,449,110): typecheck error FS3083: The static parameter 'Count' has already been given a value diff --git a/tests/fsharp/typecheck/sigs/neg24.bsl b/tests/fsharp/typecheck/sigs/neg24.bsl new file mode 100644 index 00000000000..ffc702de46b --- /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 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 of the same type as 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..6e1e072cf1a --- /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 of the same type as 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/version50/neg20.bsl b/tests/fsharp/typecheck/sigs/version50/neg20.bsl new file mode 100644 index 00000000000..4227ab07193 --- /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 of the same type as 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(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(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(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(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(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 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 of the same type as 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 of the same type as 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(202,7,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 + From 0a30a3b4f44e321ec410d788eb0b23db7d54982c Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 21 Jan 2021 14:50:36 +0000 Subject: [PATCH 15/42] adjust test baseline for better error recovery --- tests/fsharp/TypeProviderTests.fs | 6 +++--- tests/fsharp/typeProviders/negTests/neg1.bsl | 6 ++++++ .../ClassTypes/Misc/E_ExplicitConstructor.fs | 6 ++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/tests/fsharp/TypeProviderTests.fs b/tests/fsharp/TypeProviderTests.fs index 4b26147b5eb..e90b855aef7 100644 --- a/tests/fsharp/TypeProviderTests.fs +++ b/tests/fsharp/TypeProviderTests.fs @@ -224,7 +224,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"] @@ -232,11 +232,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/typeProviders/negTests/neg1.bsl b/tests/fsharp/typeProviders/negTests/neg1.bsl index 8572d60442e..3710102af10 100644 --- a/tests/fsharp/typeProviders/negTests/neg1.bsl +++ b/tests/fsharp/typeProviders/negTests/neg1.bsl @@ -1638,16 +1638,22 @@ neg1.fsx(438,109,438,110): typecheck error FS0001: This expression was expected but here has type 'string' +neg1.fsx(438,9,438,111): typecheck error FS3033: The type provider 'Provider.GoodProviderForNegativeStaticParameterTypeTests' reported an error: Specified cast is not valid. + neg1.fsx(440,119,440,120): typecheck error FS0001: This expression was expected to have type 'int' but here has type 'string' +neg1.fsx(440,19,440,121): typecheck error FS3033: The type provider 'Provider.GoodProviderForNegativeStaticParameterTypeTests' reported an error: Specified cast is not valid. + neg1.fsx(440,119,440,120): typecheck error FS0001: This expression was expected to have type 'int' but here has type 'string' +neg1.fsx(440,19,440,121): typecheck error FS3033: The type provider 'Provider.GoodProviderForNegativeStaticParameterTypeTests' reported an error: Specified cast is not valid. + neg1.fsx(448,9,448,107): typecheck error FS3148: Too many static parameters. Expected at most 1 parameters, but got 2 unnamed and 0 named parameters. neg1.fsx(449,105,449,110): typecheck error FS3083: The static parameter 'Count' has already been given a value diff --git a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_ExplicitConstructor.fs b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_ExplicitConstructor.fs index 79b41e43de2..4a2034c9c58 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_ExplicitConstructor.fs +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_ExplicitConstructor.fs @@ -7,3 +7,9 @@ type A = inherit System.Exception new (x : string) as y = { inherit System.Exception(x) }; 1 + +type B() = + static member M([] x: Quotations.Expr) = printfn "x = %A" x + +B.M(1+1) + From b6211a1c7d3a13e1abebfd82a9fb6d6b0183957a Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 21 Jan 2021 14:51:27 +0000 Subject: [PATCH 16/42] adjust test baseline for better error recovery --- .../ClassTypes/Misc/E_ExplicitConstructor.fs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_ExplicitConstructor.fs b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_ExplicitConstructor.fs index 4a2034c9c58..79b41e43de2 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_ExplicitConstructor.fs +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_ExplicitConstructor.fs @@ -7,9 +7,3 @@ type A = inherit System.Exception new (x : string) as y = { inherit System.Exception(x) }; 1 - -type B() = - static member M([] x: Quotations.Expr) = printfn "x = %A" x - -B.M(1+1) - From 326b7d592b270a941ae59928e3dabe0be928c158 Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Thu, 21 Jan 2021 23:24:19 -0800 Subject: [PATCH 17/42] Merge main to feature/auto-widen (#10918) * [main] Update dependencies from dotnet/arcade (#10913) Microsoft.DotNet.Arcade.Sdk From Version 6.0.0-beta.21068.2 -> To Version 6.0.0-beta.21069.2 Co-authored-by: dotnet-maestro[bot] * Refactor everything but the type provider tests in signature help testing (#10908) Co-authored-by: dotnet-maestro[bot] <42748379+dotnet-maestro[bot]@users.noreply.github.com> Co-authored-by: dotnet-maestro[bot] Co-authored-by: Phillip Carter --- eng/Version.Details.xml | 4 +- .../templates/post-build/post-build.yml | 3 + global.json | 2 +- .../UnitTests/SignatureHelpProviderTests.fs | 797 +++++++----------- 4 files changed, 325 insertions(+), 481 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 2442a0e8910..beaf438ff25 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,9 +3,9 @@ - + https://github.com/dotnet/arcade - 298c72b33f6f7b742b11f7b1c0ae77a043789fcf + ee0a6a7d9acc6f5886ae214b935f3e3d989235e4 diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml index bd776c7675b..375e91acdf3 100644 --- a/eng/common/templates/post-build/post-build.yml +++ b/eng/common/templates/post-build/post-build.yml @@ -147,6 +147,9 @@ stages: pipeline: $(AzDOPipelineId) buildId: $(AzDOBuildId) artifactName: PackageArtifacts + itemPattern: | + ** + !**/Microsoft.SourceBuild.Intermediate.*.nupkg # This is necessary whenever we want to publish/restore to an AzDO private feed # Since sdk-task.ps1 tries to restore packages we need to do this authentication here diff --git a/global.json b/global.json index 9c1a1af8218..f6d7cd11c3e 100644 --- a/global.json +++ b/global.json @@ -13,7 +13,7 @@ } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21068.2", + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21069.2", "Microsoft.DotNet.Helix.Sdk": "2.0.0-beta.19069.2" } } diff --git a/vsintegration/tests/UnitTests/SignatureHelpProviderTests.fs b/vsintegration/tests/UnitTests/SignatureHelpProviderTests.fs index 928ccea9b4b..8daf94328e7 100644 --- a/vsintegration/tests/UnitTests/SignatureHelpProviderTests.fs +++ b/vsintegration/tests/UnitTests/SignatureHelpProviderTests.fs @@ -1,38 +1,15 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. -// -// To run the tests in this file: -// -// Technique 1: Compile VisualFSharp.UnitTests.dll and run it as a set of unit tests -// -// Technique 2: -// -// Enable some tests in the #if EXE section at the end of the file, -// then compile this file as an EXE that has InternalsVisibleTo access into the -// appropriate DLLs. This can be the quickest way to get turnaround on updating the tests -// and capturing large amounts of structured output. -(* - cd Debug\net40\bin - .\fsc.exe --define:EXE -r:.\Microsoft.Build.Utilities.Core.dll -o VisualFSharp.UnitTests.exe -g --optimize- -r .\FSharp.Compiler.Service.dll -r .\FSharp.Editor.dll -r nunit.framework.dll ..\..\..\tests\service\FsUnit.fs ..\..\..\tests\service\Common.fs /delaysign /keyfile:..\..\..\src\fsharp\msft.pubkey ..\..\..\vsintegration\tests\UnitTests\SignatureHelpProviderTests.fs - .\VisualFSharp.UnitTests.exe -*) -// Technique 3: -// -// Use F# Interactive. This only works for FSharp.Compiler.Service.dll which has a public API [] module Microsoft.VisualStudio.FSharp.Editor.Tests.Roslyn.SignatureHelpProvider open System open System.IO -open System.Text open NUnit.Framework -open Microsoft.CodeAnalysis.Text +open Microsoft.VisualStudio.FSharp.Editor open VisualFSharp.UnitTests.Roslyn -open Microsoft.VisualStudio.FSharp.Editor - open UnitTests.TestLib.LanguageService open FSharp.Compiler.Text @@ -120,158 +97,16 @@ let GetCompletionTypeNamesFromXmlString (xml:string) = use project = CreateProject xml GetCompletionTypeNamesFromCursorPosition project -[] -let ShouldGiveSignatureHelpAtCorrectMarkers() = - let manyTestCases = - [ (""" -//1 -System.Console.WriteLine(format="Hello, {0}",arg0="World") -""", - [(".", None); - ("System", None); - ("WriteLine", None); - ("(", Some ("[7..64)", 0, 2, Some "format")); - ("format", Some ("[7..64)", 0, 2, Some "format")); - (",", None); - ("""",""", Some ("[7..64)", 1, 2, Some "arg0")); - ("arg0", Some ("[7..64)", 1, 2, Some "arg0")); - ("arg0=", Some ("[7..64)", 1, 2, Some "arg0")); - ("World", Some ("[7..64)", 1, 2, Some "arg0")); - (")", Some("[7..64)", 0, 2, Some "format"))]); - ( """ -//2 -open System -Console.WriteLine([(1,2)]) -""", - [ - ("WriteLine(", Some ("[20..45)", 0, 0, None)); - (",", None); - ("[(", Some ("[20..45)", 0, 1, None)) - ]); - ( """ -//3 -type foo = N1.T< -type foo2 = N1.T -type foo2 = N1.T -type foo3 = N1.T -type foo4 = N1.T -type foo5 = N1.T -""", - [("type foo = N1.T<", Some ("[18..24)", 0, 0, None)); - ("type foo2 = N1.T<", Some ("[40..53)", 0, 0, Some "Param1")); - ("type foo2 = N1.T Async.RunSynchronously - - if x.IsNone then - Assert.Fail("Could not parse and check document.") - x.Value - - let actual = - let paramInfoLocations = parseResults.FindNoteworthyParamInfoLocations(Pos.fromZ caretLinePos.Line caretLineColumn) - match paramInfoLocations with - | None -> None - | Some paramInfoLocations -> - let triggered = - FSharpSignatureHelpProvider.ProvideMethodsAsyncAux( - caretLinePos, - caretLineColumn, - paramInfoLocations, - checkFileResults, - DefaultDocumentationProvider, - sourceText, - caretPosition, - triggerChar) - |> Async.RunSynchronously - - checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() - match triggered with - | None -> None - | Some data -> Some (data.ApplicableSpan.ToString(),data.ArgumentIndex,data.ArgumentCount,data.ArgumentName) - - if expected <> actual then - sb.AppendLine(sprintf "FSharpCompletionProvider.ProvideMethodsAsyncAux() gave unexpected results, expected %A, got %A" expected actual) |> ignore - yield (marker, actual) ] - - printfn "(\"\"\"%s\n\"\"\",\n%s)" fileContents ((sprintf "%A" actual).Replace("null","None")) - - - match sb.ToString() with - | "" -> () - | errorText -> Assert.Fail errorText - -[] -let ``single argument function application``() = - let fileContents = """ -sqrt -""" - let marker = "sqrt " +let assertSignatureHelpForMethodCalls (fileContents: string) (marker: string) (expected: (string * int * int * string option) option) = let caretPosition = fileContents.IndexOf(marker) + marker.Length + let triggerChar = if marker ="," then Some ',' elif marker = "(" then Some '(' elif marker = "<" then Some '<' else None let sourceText = SourceText.From(fileContents) + let textLines = sourceText.Lines + let caretLinePos = textLines.GetLinePosition(caretPosition) + let caretLineColumn = caretLinePos.Character let perfOptions = LanguageServicePerformanceOptions.Default let textVersionHash = 0 - let documentId = DocumentId.CreateNewId(ProjectId.CreateNewId()) - + let parseResults, _, checkFileResults = let x = checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, projectOptions, perfOptions, "TestSignatureHelpProvider") @@ -281,50 +116,32 @@ sqrt Assert.Fail("Could not parse and check document.") x.Value - - let adjustedColumnInSource = - let rec loop s c = - if String.IsNullOrWhiteSpace(s.ToString()) then - loop (sourceText.GetSubText(c - 1)) (c - 1) - else - c - let startText = - if caretPosition = sourceText.Length then - sourceText.GetSubText(caretPosition) - else - sourceText.GetSubText(TextSpan(caretPosition, 1)) - - loop startText caretPosition - - let sigHelp = - FSharpSignatureHelpProvider.ProvideParametersAsyncAux( - parseResults, - checkFileResults, - documentId, - [], - DefaultDocumentationProvider, - sourceText, - caretPosition, - adjustedColumnInSource, - filePath) - |> Async.RunSynchronously - - checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() + let actual = + let paramInfoLocations = parseResults.FindNoteworthyParamInfoLocations(Pos.fromZ caretLinePos.Line caretLineColumn) + match paramInfoLocations with + | None -> None + | Some paramInfoLocations -> + let triggered = + FSharpSignatureHelpProvider.ProvideMethodsAsyncAux( + caretLinePos, + caretLineColumn, + paramInfoLocations, + checkFileResults, + DefaultDocumentationProvider, + sourceText, + caretPosition, + triggerChar) + |> Async.RunSynchronously + + checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() + match triggered with + | None -> None + | Some data -> Some (data.ApplicableSpan.ToString(),data.ArgumentIndex,data.ArgumentCount,data.ArgumentName) - match sigHelp with - | None -> Assert.Fail("Expected signature help") - | Some sigHelp -> - Assert.AreEqual(1, sigHelp.ArgumentCount) - Assert.AreEqual(0, sigHelp.ArgumentIndex) + Assert.AreEqual(expected, actual) -[] -let ``multi-argument function application``() = - let fileContents = """ -let add2 x y = x + y -add2 1 -""" - let marker = "add2 1 " - let caretPosition = fileContents.IndexOf(marker) + marker.Length +let assertSignatureHelpForFunctionApplication (fileContents: string) (marker: string) expectedArgumentCount expectedArgumentIndex = + let caretPosition = fileContents.LastIndexOf(marker) + marker.Length let sourceText = SourceText.From(fileContents) let perfOptions = LanguageServicePerformanceOptions.Default let textVersionHash = 0 @@ -340,18 +157,12 @@ add2 1 x.Value let adjustedColumnInSource = - let rec loop s c = - if String.IsNullOrWhiteSpace(s.ToString()) then - loop (sourceText.GetSubText(c - 1)) (c - 1) + let rec loop ch pos = + if Char.IsWhiteSpace(ch) then + loop sourceText.[pos - 1] (pos - 1) else - c - let startText = - if caretPosition = sourceText.Length then - sourceText.GetSubText(caretPosition) - else - sourceText.GetSubText(TextSpan(caretPosition, 1)) - - loop startText caretPosition + pos + loop sourceText.[caretPosition - 1] (caretPosition - 1) let sigHelp = FSharpSignatureHelpProvider.ProvideParametersAsyncAux( @@ -371,289 +182,319 @@ add2 1 match sigHelp with | None -> Assert.Fail("Expected signature help") | Some sigHelp -> - Assert.AreEqual(2, sigHelp.ArgumentCount) - Assert.AreEqual(1, sigHelp.ArgumentIndex) - -[] -let ``qualified function application``() = - let fileContents = """ -module M = - let f x = x -M.f -""" - let marker = "M.f " - let caretPosition = fileContents.IndexOf(marker) + marker.Length - let sourceText = SourceText.From(fileContents) - let perfOptions = LanguageServicePerformanceOptions.Default - let textVersionHash = 0 - let documentId = DocumentId.CreateNewId(ProjectId.CreateNewId()) - - let parseResults, _, checkFileResults = - let x = - checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, projectOptions, perfOptions, "TestSignatureHelpProvider") - |> Async.RunSynchronously + Assert.AreEqual(expectedArgumentCount, sigHelp.ArgumentCount) + Assert.AreEqual(expectedArgumentIndex, sigHelp.ArgumentIndex) - if x.IsNone then - Assert.Fail("Could not parse and check document.") - x.Value +[] +module ``Gives signature help in method calls`` = - let adjustedColumnInSource = - let rec loop s c = - if String.IsNullOrWhiteSpace(s.ToString()) then - loop (sourceText.GetSubText(c - 1)) (c - 1) - else - c - let startText = - if caretPosition = sourceText.Length then - sourceText.GetSubText(caretPosition) - else - sourceText.GetSubText(TextSpan(caretPosition, 1)) - - loop startText caretPosition + [] + let ``dot``() = + let fileContents = """ +//1 +System.Console.WriteLine(format="Hello, {0}",arg0="World") +""" + let marker = "." + assertSignatureHelpForMethodCalls fileContents marker None - let sigHelp = - FSharpSignatureHelpProvider.ProvideParametersAsyncAux( - parseResults, - checkFileResults, - documentId, - [], - DefaultDocumentationProvider, - sourceText, - caretPosition, - adjustedColumnInSource, - filePath) - |> Async.RunSynchronously + [] + let ``System``() = + let fileContents = """ +//1 +System.Console.WriteLine(format="Hello, {0}",arg0="World") +""" + let marker = "System" + assertSignatureHelpForMethodCalls fileContents marker None - checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() + [] + let ``WriteLine``() = + let fileContents = """ +//1 +System.Console.WriteLine(format="Hello, {0}",arg0="World") +""" + let marker = "WriteLine" + assertSignatureHelpForMethodCalls fileContents marker None - match sigHelp with - | None -> Assert.Fail("Expected signature help") - | Some sigHelp -> - Assert.AreEqual(1, sigHelp.ArgumentCount) - Assert.AreEqual(0, sigHelp.ArgumentIndex) + [] + let ``open paren``() = + let fileContents = """ +//1 +System.Console.WriteLine(format="Hello, {0}",arg0="World") +""" + let marker = "(" + assertSignatureHelpForMethodCalls fileContents marker (Some ("[7..64)", 0, 2, Some "format")) -[] -let ``function application in single pipeline with no additional args``() = - let fileContents = """ -[1..10] |> id + [] + let ``named arg``() = + let fileContents = """ +//1 +System.Console.WriteLine(format="Hello, {0}",arg0="World") """ - let marker = "id " - let caretPosition = fileContents.IndexOf(marker) + marker.Length - let sourceText = SourceText.From(fileContents) - let perfOptions = LanguageServicePerformanceOptions.Default - let textVersionHash = 0 - let documentId = DocumentId.CreateNewId(ProjectId.CreateNewId()) - - let parseResults, _, checkFileResults = - let x = - checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, projectOptions, perfOptions, "TestSignatureHelpProvider") - |> Async.RunSynchronously + let marker = "format" + assertSignatureHelpForMethodCalls fileContents marker (Some ("[7..64)", 0, 2, Some "format")) - if x.IsNone then - Assert.Fail("Could not parse and check document.") - x.Value - - let adjustedColumnInSource = - let rec loop s c = - if String.IsNullOrWhiteSpace(s.ToString()) then - loop (sourceText.GetSubText(c - 1)) (c - 1) - else - c - let startText = - if caretPosition = sourceText.Length then - sourceText.GetSubText(caretPosition) - else - sourceText.GetSubText(TextSpan(caretPosition, 1)) - - loop startText caretPosition + [] + let ``comma``() = + let fileContents = """ +//1 +System.Console.WriteLine(format="Hello, {0}",arg0="World") +""" + let marker = "," + assertSignatureHelpForMethodCalls fileContents marker None - let sigHelp = - FSharpSignatureHelpProvider.ProvideParametersAsyncAux( - parseResults, - checkFileResults, - documentId, - [], - DefaultDocumentationProvider, - sourceText, - caretPosition, - adjustedColumnInSource, - filePath) - |> Async.RunSynchronously + [] + let ``second comma``() = + let fileContents = """ +//1 +System.Console.WriteLine(format="Hello, {0}",arg0="World") +""" + assertSignatureHelpForMethodCalls fileContents """",""" (Some ("[7..64)", 1, 2, Some "arg0")) - checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() + [] + let ``second named arg``() = + let fileContents = """ +//1 +System.Console.WriteLine(format="Hello, {0}",arg0="World") +""" + let marker = "arg0" + assertSignatureHelpForMethodCalls fileContents marker (Some ("[7..64)", 1, 2, Some "arg0")) - Assert.True(sigHelp.IsNone, "No signature help is expected because there are no additional args to apply.") + [] + let ``second named arg equals``() = + let fileContents = """ +//1 +System.Console.WriteLine(format="Hello, {0}",arg0="World") +""" + let marker = "arg0=" + assertSignatureHelpForMethodCalls fileContents marker (Some ("[7..64)", 1, 2, Some "arg0")) -[] -let ``function application in single pipeline with an additional argument``() = - let fileContents = """ -[1..10] |> List.map + [] + let ``World``() = + let fileContents = """ +//1 +System.Console.WriteLine(format="Hello, {0}",arg0="World") """ - let marker = "List.map " - let caretPosition = fileContents.IndexOf(marker) + marker.Length - let sourceText = SourceText.From(fileContents) - let perfOptions = LanguageServicePerformanceOptions.Default - let textVersionHash = 0 - let documentId = DocumentId.CreateNewId(ProjectId.CreateNewId()) - - let parseResults, _, checkFileResults = - let x = - checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, projectOptions, perfOptions, "TestSignatureHelpProvider") - |> Async.RunSynchronously + let marker = "World" + assertSignatureHelpForMethodCalls fileContents marker (Some ("[7..64)", 1, 2, Some "arg0")) - if x.IsNone then - Assert.Fail("Could not parse and check document.") - x.Value - - let adjustedColumnInSource = - let rec loop s c = - if String.IsNullOrWhiteSpace(s.ToString()) then - loop (sourceText.GetSubText(c - 1)) (c - 1) - else - c - let startText = - if caretPosition = sourceText.Length then - sourceText.GetSubText(caretPosition) - else - sourceText.GetSubText(TextSpan(caretPosition, 1)) - - loop startText caretPosition + [] + let ``end paren``() = + let fileContents = """ +//1 +System.Console.WriteLine(format="Hello, {0}",arg0="World") + """ + let marker = ")" + assertSignatureHelpForMethodCalls fileContents marker (Some("[7..64)", 0, 2, Some "format")) + +[] +module ``Signature help with list literals, parens, etc`` = + [] + let ``Open paren``() = + let fileContents = """ +//2 +open System +Console.WriteLine([(1,2)]) +""" + let marker = "WriteLine(" + assertSignatureHelpForMethodCalls fileContents marker (Some ("[20..45)", 0, 0, None)) - let sigHelp = - FSharpSignatureHelpProvider.ProvideParametersAsyncAux( - parseResults, - checkFileResults, - documentId, - [], - DefaultDocumentationProvider, - sourceText, - caretPosition, - adjustedColumnInSource, - filePath) - |> Async.RunSynchronously + [] + let ``comma``() = + let fileContents = """ +//2 +open System +Console.WriteLine([(1,2)]) +""" + let marker = "," + assertSignatureHelpForMethodCalls fileContents marker None - checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() + [] + let ``list and tuple bracket pair start``() = + let fileContents = """ +//2 +open System +Console.WriteLine([(1,2)]) +""" + let marker = "[(" + assertSignatureHelpForMethodCalls fileContents marker (Some ("[20..45)", 0, 1, None)) + +[] +module ``Unfinished parentheses`` = + [] + let ``Unfinished parentheses``() = + let fileContents = """ +let _ = System.DateTime( +""" + let marker = "let _ = System.DateTime(" + assertSignatureHelpForMethodCalls fileContents marker (Some ("[10..26)", 0, 0, None)) - match sigHelp with - | None -> Assert.Fail("Expected signature help") - | Some sigHelp -> - Assert.AreEqual(1, sigHelp.ArgumentCount) - Assert.AreEqual(0, sigHelp.ArgumentIndex) + [] + let ``Unfinished parentheses with comma``() = + let fileContents = """ +let _ = System.DateTime(1L, +""" + let marker = "let _ = System.DateTime(1L," + assertSignatureHelpForMethodCalls fileContents marker (Some ("[10..31)", 1, 2, None )) [] -let ``function application in middle of pipeline with an additional argument``() = - let fileContents = """ -[1..10] -|> List.map -|> List.filer (fun x -> x > 3) -""" - let marker = "List.map " - let caretPosition = fileContents.IndexOf(marker) + marker.Length - let sourceText = SourceText.From(fileContents) - let perfOptions = LanguageServicePerformanceOptions.Default - let textVersionHash = 0 - let documentId = DocumentId.CreateNewId(ProjectId.CreateNewId()) - - let parseResults, _, checkFileResults = - let x = - checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, projectOptions, perfOptions, "TestSignatureHelpProvider") - |> Async.RunSynchronously +let ``type provider static parameter tests``() = + // This is old code and I'm too lazy to move it all out. - Phillip Carter + let manyTestCases = + [ + ( """ +//3 +type foo = N1.T< +type foo2 = N1.T +type foo2 = N1.T +type foo3 = N1.T +type foo4 = N1.T +type foo5 = N1.T +""", + [("type foo = N1.T<", Some ("[18..24)", 0, 0, None)); + ("type foo2 = N1.T<", Some ("[40..53)", 0, 0, Some "Param1")); + ("type foo2 = N1.T] +module ``Function argument applications`` = + [] + let ``single argument function application``() = + let fileContents = """ +sqrt + """ + let marker = "sqrt " + assertSignatureHelpForFunctionApplication fileContents marker 1 0 - let sigHelp = - FSharpSignatureHelpProvider.ProvideParametersAsyncAux( - parseResults, - checkFileResults, - documentId, - [], - DefaultDocumentationProvider, - sourceText, - caretPosition, - adjustedColumnInSource, - filePath) - |> Async.RunSynchronously + [] + let ``multi-argument function application``() = + let fileContents = """ +let add2 x y = x + y +add2 1 + """ + let marker = "add2 1 " + assertSignatureHelpForFunctionApplication fileContents marker 2 1 - checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() + [] + let ``qualified function application``() = + let fileContents = """ +module M = + let f x = x +M.f + """ + let marker = "M.f " + assertSignatureHelpForFunctionApplication fileContents marker 1 0 - match sigHelp with - | None -> Assert.Fail("Expected signature help") - | Some sigHelp -> - Assert.AreEqual(1, sigHelp.ArgumentCount) - Assert.AreEqual(0, sigHelp.ArgumentIndex) + [] + let ``function application in single pipeline with no additional args``() = + let fileContents = """ +[1..10] |> id + """ + let marker = "id " + let caretPosition = fileContents.IndexOf(marker) + marker.Length + let sourceText = SourceText.From(fileContents) + let perfOptions = LanguageServicePerformanceOptions.Default + let textVersionHash = 0 + let documentId = DocumentId.CreateNewId(ProjectId.CreateNewId()) + + let parseResults, _, checkFileResults = + let x = + checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, projectOptions, perfOptions, "TestSignatureHelpProvider") + |> Async.RunSynchronously -[] -let ``function application with function as parameter``() = - let fileContents = """ -let derp (f: int -> int -> int) x = f x 1 -derp -""" - let marker = "derp " - let caretPosition = fileContents.LastIndexOf(marker) + marker.Length - let sourceText = SourceText.From(fileContents) - let perfOptions = LanguageServicePerformanceOptions.Default - let textVersionHash = 0 - let documentId = DocumentId.CreateNewId(ProjectId.CreateNewId()) + if x.IsNone then + Assert.Fail("Could not parse and check document.") + x.Value - let parseResults, _, checkFileResults = - let x = - checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText, projectOptions, perfOptions, "TestSignatureHelpProvider") + let adjustedColumnInSource = + let rec loop ch pos = + if Char.IsWhiteSpace(ch) then + loop sourceText.[pos - 1] (pos - 1) + else + pos + loop sourceText.[caretPosition - 1] (caretPosition - 1) + + let sigHelp = + FSharpSignatureHelpProvider.ProvideParametersAsyncAux( + parseResults, + checkFileResults, + documentId, + [], + DefaultDocumentationProvider, + sourceText, + caretPosition, + adjustedColumnInSource, + filePath) |> Async.RunSynchronously - if x.IsNone then - Assert.Fail("Could not parse and check document.") - x.Value - - let adjustedColumnInSource = - let rec loop s c = - if String.IsNullOrWhiteSpace(s.ToString()) then - loop (sourceText.GetSubText(c - 1)) (c - 1) - else - c - let startText = - if caretPosition = sourceText.Length then - sourceText.GetSubText(caretPosition) - else - sourceText.GetSubText(TextSpan(caretPosition, 1)) - - loop startText caretPosition + checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() - let sigHelp = - FSharpSignatureHelpProvider.ProvideParametersAsyncAux( - parseResults, - checkFileResults, - documentId, - [], - DefaultDocumentationProvider, - sourceText, - caretPosition, - adjustedColumnInSource, - filePath) - |> Async.RunSynchronously + Assert.True(sigHelp.IsNone, "No signature help is expected because there are no additional args to apply.") - checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() + [] + let ``function application in single pipeline with an additional argument``() = + let fileContents = """ +[1..10] |> List.map + """ + let marker = "List.map " + assertSignatureHelpForFunctionApplication fileContents marker 1 0 - match sigHelp with - | None -> Assert.Fail("Expected signature help") - | Some sigHelp -> - Assert.AreEqual(2, sigHelp.ArgumentCount) - Assert.AreEqual(0, sigHelp.ArgumentIndex) + [] + let ``function application in middle of pipeline with an additional argument``() = + let fileContents = """ +[1..10] +|> List.map +|> List.filer (fun x -> x > 3) + """ + let marker = "List.map " + assertSignatureHelpForFunctionApplication fileContents marker 1 0 + + [] + let ``function application with function as parameter``() = + let fileContents = """ +let derp (f: int -> int -> int) x = f x 1 +derp +""" + let marker = "derp " + assertSignatureHelpForFunctionApplication fileContents marker 2 0 // migrated from legacy test [] From a5fb84c9b206f656049f078cce160298ac02ad19 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 25 Jan 2021 15:57:45 +0000 Subject: [PATCH 18/42] fixes for type directed conversion for optional args, backwards compat for overloads --- src/fsharp/CheckExpressions.fs | 205 +++++++++++------- src/fsharp/ConstraintSolver.fs | 229 +++++++++++++------- src/fsharp/ErrorLogger.fs | 5 +- src/fsharp/ErrorLogger.fsi | 4 +- src/fsharp/MethodCalls.fs | 181 ++++++++++------ src/fsharp/MethodCalls.fsi | 36 ++- tests/fsharp/core/auto-widen/auto-widen.fsx | 223 +++++++++++++++++++ 7 files changed, 656 insertions(+), 227 deletions(-) create mode 100644 tests/fsharp/core/auto-widen/auto-widen.fsx diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index defaeb19326..c35a4d8d66f 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -457,15 +457,19 @@ let UnifyTypes cenv (env: TcEnv) m actualTy expectedTy = // then allow subsumption. let UnifyOverallType cenv (env: TcEnv) m overallTy actualTy = match overallTy with - | MustConvertTo(overallTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion && not (isSealedTy cenv.g overallTy) -> + | MustConvertTo(reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion -> let actualTy = tryNormalizeMeasureInType cenv.g actualTy - let overallTy = tryNormalizeMeasureInType cenv.g overallTy - if AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy actualTy then - () - elif AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy actualTy then + let reqdTy = tryNormalizeMeasureInType cenv.g reqdTy + if AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css m reqdTy actualTy then () else - UnifyTypes cenv env m overallTy actualTy + // try adhoc type-directed conversions + let reqdTy2, _usesTDC = AdjustRequiredTypeForTypeDirectedConversions cenv.infoReader false reqdTy actualTy m + if AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m reqdTy2 actualTy then + () + else + // report the error + UnifyTypes cenv env m reqdTy actualTy | _ -> UnifyTypes cenv env m overallTy.Commit actualTy @@ -5438,19 +5442,46 @@ and TcExprUndelayedNoType cenv env tpenv synExpr: Expr * TType * _ = let expr, tpenv = TcExprUndelayed cenv (MustEqual overallTy) env tpenv synExpr expr, overallTy, tpenv -and TcExprLeafProtectExcept p cenv (overallTy: OverallTy) (env: TcEnv) m f = +and TcExprLeafProtectExcept2 p cenv (overallTy: OverallTy) actualTy (env: TcEnv) canAdhoc m f = match overallTy with - | MustConvertTo(oty) when cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion && not (p oty) && not (isSealedTy cenv.g oty) -> - let oty2 = NewInferenceType() - AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace oty oty2 - let expr, tpenv = f oty2 - let expr2 = mkCoerceIfNeeded cenv.g oty oty2 expr + | MustConvertTo(reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion && not (p reqdTy) -> + // Note about the cases where canAdhoc=false: + // Some constructs (list expressions etc) require placing the subtype constraint down + // before processing in order to propagate into the construct. + // + // These do not support adhoc conversions + // + // TBD: consider removing canAdhoc and program those cases separately + // + // Note about the cases where canAdhoc=true: + // + // This assumes the processing of the construct is independent of overallTy, and we can just pass a type + // variable then check for adhoc and subsumption conversions after. + if not canAdhoc then + AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace reqdTy actualTy + let expr, tpenv = f () + if canAdhoc then + let reqdTy2, _usesTDC = AdjustRequiredTypeForTypeDirectedConversions cenv.infoReader false reqdTy actualTy m + AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace reqdTy2 actualTy + let expr2 = AdjustExprForTypeDirectedConversions cenv.g cenv.amap cenv.infoReader env.AccessRights reqdTy actualTy m expr expr2, tpenv + | _ -> + UnifyTypes cenv env m overallTy.Commit actualTy + f () + +and TcExprLeafProtectExcept p cenv (overallTy: OverallTy) (env: TcEnv) canAdhoc m f = + match overallTy with + | MustConvertTo(reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion && not (p reqdTy) -> + let actualTy = NewInferenceType() + TcExprLeafProtectExcept2 p cenv overallTy actualTy env canAdhoc m (fun () -> f actualTy) | _ -> f overallTy.Commit -and TcExprLeafProtect cenv overallTy env m f = - TcExprLeafProtectExcept (fun _ -> false) cenv overallTy env m f +and TcExprLeafProtect cenv overallTy env canAdhoc m f = + TcExprLeafProtectExcept (fun _ -> false) cenv overallTy env canAdhoc m f + +and TcExprLeafProtect2 cenv overallTy actualTy env canAdhoc m f = + TcExprLeafProtectExcept2 (fun _ -> false) cenv overallTy actualTy env canAdhoc m f and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = @@ -5465,20 +5496,16 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = | SynExpr.DotIndexedGet _ | SynExpr.DotIndexedSet _ | SynExpr.TypeApp _ | SynExpr.Ident _ | SynExpr.LongIdent _ | SynExpr.App _ | SynExpr.DotGet _ -> error(Error(FSComp.SR.tcExprUndelayed(), synExpr.Range)) - | SynExpr.Const (SynConst.String (s, m), mWholeExpr) -> - TcExprLeafProtect cenv overallTy env mWholeExpr (fun overallTy -> - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights) - TcConstStringExpr cenv overallTy env m tpenv s - ) + | SynExpr.Const (SynConst.String (s, m), _mWholeExpr) -> + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) + TcConstStringExpr cenv overallTy env m tpenv s | SynExpr.InterpolatedString (parts, m) -> - TcExprLeafProtect cenv overallTy env m (fun overallTy -> - checkLanguageFeatureError cenv.g.langVersion LanguageFeature.StringInterpolation 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 - ) + TcInterpolatedStringExpr cenv overallTy env m tpenv parts | SynExpr.Const (synConst, m) -> CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) @@ -5530,10 +5557,10 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = // Type annotations stemming from expression annotations are rigid, e.g. this is // not allowed: // (1 : obj) - let overallTyInner = (* if isFromReturnAnnotation then *) MustConvertTo tgtTy (* else MustEqual tgtTy *) - let bodyExpr, tpenv = TcExpr cenv overallTyInner env tpenv synBodyExpr - let bodyExpr = mkCoerceIfNeeded cenv.g overallTy.Commit overallTyInner.Commit bodyExpr - bodyExpr, tpenv + //let overallTyInner = (* if isFromReturnAnnotation then *) MustConvertTo tgtTy (* else MustEqual tgtTy *) + let bodyExpr, tpenv = TcExpr cenv (MustConvertTo tgtTy) env tpenv synBodyExpr + let bodyExpr2 = AdjustExprForTypeDirectedConversions cenv.g cenv.amap cenv.infoReader env.AccessRights overallTy.Commit tgtTy m bodyExpr + bodyExpr2, tpenv // e :? ty | SynExpr.TypeTest (synInnerExpr, tgtTy, m) -> @@ -5594,7 +5621,7 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = expr, tpenv | SynExpr.Tuple (isExplicitStruct, args, _, m) -> - TcExprLeafProtectExcept (isAnyTupleTy cenv.g) cenv overallTy env m (fun overallTy -> + TcExprLeafProtectExcept (isAnyTupleTy cenv.g) cenv overallTy env true m (fun overallTy -> let tupInfo, argTys = UnifyTupleTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv m overallTy isExplicitStruct args let flexes = argTys |> List.map (fun _ -> false) @@ -5604,16 +5631,29 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = ) | SynExpr.AnonRecd (isStruct, optOrigExpr, unsortedFieldExprs, mWholeExpr) -> - TcExprLeafProtect cenv overallTy env mWholeExpr (fun overallTy -> + TcExprLeafProtectExcept (isAnonRecdTy cenv.g) cenv overallTy env true mWholeExpr (fun overallTy -> TcAnonRecdExpr cenv overallTy env tpenv (isStruct, optOrigExpr, unsortedFieldExprs, mWholeExpr) ) | SynExpr.ArrayOrList (isArray, args, m) -> - TcExprLeafProtect cenv overallTy env m (fun overallTy -> - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.AccessRights) - - let argty = NewInferenceType () - UnifyTypes cenv env m overallTy (if isArray then mkArrayType cenv.g argty else mkListTy cenv.g argty) + 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 + + // Note, allowing canAdhoc = true would disable subtype-based propagation from overallTy into checking of structure + // + // For example + // let x : A seq = [ B(); B() ] + // let x : B seq = [ B(); B() ] + // let x : A list = [ B(); B() ] + // let x : B list = [ B(); B() ] + // but consider the case where there is no relation but an op_Implicit is enabled from List<_> to C + // let x : C = [ B(); B() ] + // + // So op_Implicit is effectively disabled for direct uses of list expressions etc. + let canAdhoc = false //not (AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy.Commit actualTy) + + TcExprLeafProtect2 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) @@ -5634,19 +5674,35 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = ) | SynExpr.New (superInit, synObjTy, arg, mNewExpr) -> - TcExprLeafProtect cenv overallTy env mNewExpr (fun overallTy -> - 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 + + // For consistency, op_Implicit is effectively disabled for direct uses of 'new' expressions + let canAdhoc = false + + TcExprLeafProtect2 cenv overallTy objTy env canAdhoc mNewExpr (fun () -> TcNewExpr cenv env tpenv objTy (Some synObjTy.Range) superInit arg mNewExpr ) | SynExpr.ObjExpr (objTy, argopt, binds, extraImpls, mNewExpr, m) -> - TcExprLeafProtect cenv overallTy env m (fun overallTy -> - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.eAccessRights) + 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 //not (AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy.Commit actualTy) + + TcExprLeafProtect cenv overallTy env canAdhoc m (fun overallTy -> TcObjectExpr cenv overallTy env tpenv (objTy, argopt, binds, extraImpls, mNewExpr, m) ) | SynExpr.Record (inherits, optOrigExpr, flds, mWholeExpr) -> + + // NOTE: TcExprLeafProtect is not used here because record expressions are used for class initialization where placing the subtype constraint is not enough + // TODO: allow subsumption for normal record expressions + //TcExprLeafProtect cenv overallTy env mWholeExpr (fun overallTy -> CallExprHasTypeSink cenv.tcSink (mWholeExpr, env.NameEnv, overallTy.Commit, env.AccessRights) TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr) @@ -5678,16 +5734,12 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = TcForEachExpr cenv overallTy env tpenv (pat, enumSynExpr, bodySynExpr, m, spForLoop) | SynExpr.CompExpr (isArrayOrList, isNotNakedRefCell, comp, m) -> - TcExprLeafProtect cenv overallTy env m (fun overallTy -> let env = ExitFamilyRegion env - cenv.TcSequenceExpressionEntry cenv env (MustEqual overallTy) tpenv (isArrayOrList, isNotNakedRefCell, comp) m - ) + cenv.TcSequenceExpressionEntry cenv env overallTy tpenv (isArrayOrList, isNotNakedRefCell, comp) m | SynExpr.ArrayOrListOfSeqExpr (isArray, comp, m) -> - TcExprLeafProtect cenv overallTy env m (fun overallTy -> - CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy, env.eAccessRights) - cenv.TcArrayOrListSequenceExpression cenv env (MustEqual overallTy) tpenv (isArray, comp) m - ) + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.eAccessRights) + cenv.TcArrayOrListSequenceExpression cenv env overallTy tpenv (isArray, comp) m | SynExpr.LetOrUse _ -> TcLinearExprs (TcExprThatCanBeCtorBody cenv) cenv env overallTy tpenv false synExpr (fun x -> x) @@ -5807,7 +5859,7 @@ and TcExprUndelayed cenv (overallTy: 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) -> - TcExprLeafProtect cenv overallTy env m (fun overallTy -> + TcExprLeafProtect cenv overallTy env true m (fun overallTy -> 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 @@ -5826,7 +5878,7 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = ) | SynExpr.LibraryOnlyUnionCaseFieldGet (e1, c, n, m) -> - TcExprLeafProtect cenv overallTy env m (fun overallTy -> + TcExprLeafProtect cenv overallTy env true m (fun overallTy -> 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)), @@ -6618,14 +6670,14 @@ and TcObjectExpr cenv (overallTy: TType) env tpenv (synObjTy, argopt, binds, ext //------------------------------------------------------------------------- /// Check a constant string expression. It might be a 'printf' format string -and TcConstStringExpr cenv (overallTy: TType) 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 () @@ -6635,7 +6687,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 @@ -6658,11 +6710,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 + TcExprLeafProtect2 cenv overallTy g.string_ty env true m (fun () -> + mkString g m fmtString, tpenv + ) /// Check an interpolated string expression -and TcInterpolatedStringExpr cenv (overallTy: TType) env m tpenv (parts: SynInterpolatedStringPart list) = +and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: SynInterpolatedStringPart list) = let g = cenv.g let synFillExprs = @@ -6696,12 +6749,12 @@ and TcInterpolatedStringExpr cenv (overallTy: TType) env m tpenv (parts: SynInte 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 @@ -6709,14 +6762,14 @@ and TcInterpolatedStringExpr cenv (overallTy: TType) env m tpenv (parts: SynInte 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 @@ -6730,15 +6783,13 @@ and TcInterpolatedStringExpr cenv (overallTy: TType) env m tpenv (parts: SynInte | 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) @@ -6816,7 +6867,9 @@ and TcInterpolatedStringExpr cenv (overallTy: TType) env m tpenv (parts: SynInte if isString then // Make the call to sprintf - mkCall_sprintf g m printerTy fmtExpr [], tpenv + TcExprLeafProtect2 cenv overallTy g.string_ty env true m (fun () -> + mkCall_sprintf g m printerTy fmtExpr [], tpenv + ) else fmtExpr, tpenv @@ -6836,7 +6889,7 @@ and TcInterpolatedStringExpr cenv (overallTy: TType) env m tpenv (parts: SynInte 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 @@ -6852,13 +6905,14 @@ and TcConstExpr cenv (overallTy: OverallTy) env m tpenv c = // NOTE: these aren't "really" constants | SynConst.Bytes (bytes, m) -> - TcExprLeafProtect cenv overallTy env m <| fun overallTy -> + TcExprLeafProtect cenv overallTy env true m <| fun overallTy -> UnifyTypes cenv env m overallTy (mkByteArrayTy cenv.g) Expr.Op (TOp.Bytes bytes, [], [], m), tpenv | SynConst.UInt16s arr -> - TcExprLeafProtect cenv overallTy env m <| fun overallTy -> - UnifyTypes cenv env m overallTy (mkArrayType cenv.g cenv.g.uint16_ty); Expr.Op (TOp.UInt16s arr, [], [], m), tpenv + TcExprLeafProtect cenv overallTy env true m <| fun overallTy -> + UnifyTypes cenv env m overallTy (mkArrayType cenv.g cenv.g.uint16_ty) + Expr.Op (TOp.UInt16s arr, [], [], m), tpenv | SynConst.UserNum (s, suffix) -> let expr = @@ -6893,7 +6947,7 @@ and TcConstExpr cenv (overallTy: OverallTy) env m tpenv c = TcExpr cenv overallTy env tpenv expr | _ -> - TcExprLeafProtect cenv overallTy env m <| fun overallTy -> + TcExprLeafProtect cenv overallTy env true m <| fun overallTy -> let c' = TcConst cenv overallTy m env c Expr.Const (c', m, overallTy), tpenv @@ -7406,7 +7460,8 @@ and TcDelayed cenv (overallTy: OverallTy) env tpenv mExpr expr exprty (atomicFla | DelayedDot :: _ -> // at the end of the application chain allow coercion introduction UnifyOverallTypeAndRecover cenv env mExpr overallTy exprty - mkCoerceIfNeeded cenv.g overallTy.Commit exprty expr.Expr, tpenv + let expr2 = AdjustExprForTypeDirectedConversions cenv.g cenv.amap cenv.infoReader env.AccessRights overallTy.Commit exprty 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 @@ -9004,7 +9059,7 @@ 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 = MethodCalls.AdjustCallerArgExprForCoercions cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr + let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExpr 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]) @@ -9013,7 +9068,7 @@ 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 = MethodCalls.AdjustCallerArgExprForCoercions cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr + let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExpr 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 @@ -9021,7 +9076,7 @@ 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 = MethodCalls.AdjustCallerArgExprForCoercions cenv.g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr + let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExpr 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 diff --git a/src/fsharp/ConstraintSolver.fs b/src/fsharp/ConstraintSolver.fs index c8951b6ecf5..783de7649b6 100644 --- a/src/fsharp/ConstraintSolver.fs +++ b/src/fsharp/ConstraintSolver.fs @@ -488,7 +488,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 @@ -2252,11 +2252,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 + (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<_>): ImperativeOperationResult = + (calledMeth: CalledMeth<_>): OperationResult = trackErrors { let g = csenv.g let amap = csenv.amap @@ -2274,41 +2275,55 @@ 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 = AtLeastOne2D 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)) + else + return! ErrorD(Error (FSComp.SR.csMemberIsNotInstance(minfo.LogicalName), m)) + else + return! AtLeastOne2D subsumeTypes calledObjArgTys callerObjArgTys + } - if calledObjArgTys.Length <> callerObjArgTys.Length then - if calledObjArgTys.Length <> 0 then - return! ErrorD(Error (FSComp.SR.csMemberIsNotStatic(minfo.LogicalName), m)) + let! usesTDC3 = + calledMeth.ArgSets |> AtLeastOneD (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! AtLeastOne2D 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 |> AtLeastOneD (fun callerArg -> + subsumeOrConvertArg (CalledArg((0, 0), false, NotOptional, NoCallerInfo, false, false, None, reflArgInfo, paramArrayElemTy)) callerArg) + | _ -> ResultD false + else + ResultD false + | _ -> ResultD false + + let! usesTDC5 = + calledMeth.ArgSets |> AtLeastOneD (fun argSet -> + argSet.AssignedNamedArgs |> AtLeastOneD (fun arg -> + subsumeOrConvertArg arg.CalledArg arg.CallerArg)) + + let! usesTDC6 = + assignedItemSetters |> AtLeastOneD (fun (AssignedItemSetter(_, item, caller)) -> let name, calledArgTy = match item with | AssignedPropSetter(_, pminfo, pminst) -> @@ -2324,20 +2339,25 @@ 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 + 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 (MustConvertTo(overallTy)) when g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion && not (isSealedTy g overallTy) -> - let methodRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling - return! subsumeTypes overallTy methodRetTy - | Some reqdRetTy -> - let methodRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling - return! unifyTypes reqdRetTy.Commit methodRetTy - | _ -> () + let! usesTDC7 = + match reqdRetTyOpt with + | Some _ when ( (* minfo.IsConstructor || *) not alwaysCheckReturn && isNil unnamedCalledOutArgs) -> ResultD false + | Some (MustConvertTo(reqdTy)) when g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion -> + let methodRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling + subsumeOrConvertTypes reqdTy methodRetTy + | Some reqdRetTy -> + let methodRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling + unifyTypes reqdRetTy.Commit methodRetTy + | _ -> + ResultD false + return usesTDC1 || usesTDC2 || usesTDC3 || usesTDC4 || usesTDC5 || usesTDC6 || usesTDC7 + } // Assert a subtype constraint, and wrap an ErrorsFromAddingSubsumptionConstraint error around any failure @@ -2361,7 +2381,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 @@ -2382,29 +2402,54 @@ and ArgsMustSubsumeOrConvert let g = csenv.g let m = callerArg.Range - let calledArgTy = AdjustCalledArgType csenv.InfoReader isConstraint enforceNullableOptionalsKnownTypes calledArg callerArg + let calledArgTy, usesTDC = AdjustCalledArgType csenv.InfoReader isConstraint enforceNullableOptionalsKnownTypes calledArg callerArg 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 + trackErrors { + do! SolveTypeEqualsTypeWithReport csenv ndeep csenv.m trace cxsln ty1 ty2 + return false + } and MustUnifyInsideUndo csenv ndeep trace cxsln ty1 ty2 = - SolveTypeEqualsTypeWithReport csenv ndeep csenv.m (WithTrace trace) cxsln ty1 ty2 + trackErrors { + do! SolveTypeEqualsTypeWithReport csenv ndeep csenv.m (WithTrace trace) cxsln ty1 ty2 + return false + } 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)) + trackErrors { + let calledArgTy, usesTDC = AdjustCalledArgType csenv.InfoReader isConstraint true calledArg callerArg + do! SolveTypeSubsumesTypeWithWrappedContextualReport csenv ndeep m (WithTrace trace) cxsln calledArgTy callerArgTy (fun e -> ArgDoesNotMatchError(e :?> _, calledMeth, calledArg, callerArg)) + return usesTDC + } -and TypesMustSubsumeOrConvertInsideUndo (csenv: ConstraintSolverEnv) ndeep trace cxsln m calledArgTy callerArgTy = - SolveTypeSubsumesTypeWithReport csenv ndeep m trace cxsln calledArgTy callerArgTy +and TypesMustSubsumeInsideUndo (csenv: ConstraintSolverEnv) ndeep trace cxsln m calledArgTy callerArgTy = + trackErrors { + do! SolveTypeSubsumesTypeWithReport csenv ndeep m trace cxsln calledArgTy callerArgTy + return false + } -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 TypesMustSubsumeOrConvertInsideUndo (csenv: ConstraintSolverEnv) ndeep trace cxsln isConstraint m reqdTy actualTy = + trackErrors { + let reqdTy, usesTDC = AdjustRequiredTypeForTypeDirectedConversions csenv.InfoReader isConstraint reqdTy actualTy m + do! SolveTypeSubsumesTypeWithReport csenv ndeep m trace cxsln reqdTy actualTy + return usesTDC + } + +and ArgsEquivOrConvertInsideUndo (csenv: ConstraintSolverEnv) isConstraint calledArg (CallerArg(callerArgTy, m, _, _) as callerArg) = + trackErrors { + let calledArgTy, usesTDC = AdjustCalledArgType csenv.InfoReader isConstraint true calledArg callerArg + 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 = @@ -2540,6 +2585,7 @@ and ResolveOverloading calledMethGroup // The set of methods being called permitOptArgs // Can we supply optional arguments? (reqdRetTyOpt: OverallTy option) // The expected return type, if known + : CalledMeth option * OperationResult = let g = csenv.g let amap = csenv.amap @@ -2578,12 +2624,13 @@ and ResolveOverloading permitOptArgs alwaysCheckReturn (MustUnifyInsideUndo csenv ndeep newTrace cxsln) - (TypesMustSubsumeOrConvertInsideUndo csenv ndeep (WithTrace newTrace) cxsln m) - (ArgsEquivInsideUndo csenv cx.IsSome) + (TypesMustSubsumeInsideUndo csenv ndeep (WithTrace newTrace) cxsln m) + (TypesMustSubsumeOrConvertInsideUndo csenv ndeep (WithTrace newTrace) cxsln cx.IsSome m) + (ArgsEquivOrConvertInsideUndo csenv cx.IsSome) reqdRetTyOpt calledMeth) with - | [(calledMeth, warns, _)] -> - Some calledMeth, OkResult (warns, ()), NoTrace // Can't re-play the trace since ArgsEquivInsideUndo was used + | [(calledMeth, warns, _, _usesTDC)] -> + Some calledMeth, OkResult (warns, ()), NoTrace // Can't re-play the trace since ArgsEquivOrConvertInsideUndo was used | _ -> // Now determine the applicable methods. @@ -2595,7 +2642,8 @@ and ResolveOverloading permitOptArgs alwaysCheckReturn (MustUnifyInsideUndo csenv ndeep newTrace cxsln) - (TypesMustSubsumeOrConvertInsideUndo csenv ndeep (WithTrace newTrace) cxsln m) + (TypesMustSubsumeInsideUndo csenv ndeep (WithTrace newTrace) cxsln m) + (TypesMustSubsumeOrConvertInsideUndo csenv ndeep (WithTrace newTrace) cxsln cx.IsSome m) (ArgsMustSubsumeOrConvertInsideUndo csenv ndeep newTrace cxsln cx.IsSome candidate) reqdRetTyOpt candidate) @@ -2631,7 +2679,8 @@ and ResolveOverloading permitOptArgs alwaysCheckReturn (MustUnifyInsideUndo csenv ndeep newTrace cxsln) - (TypesMustSubsumeOrConvertInsideUndo csenv ndeep (WithTrace newTrace) cxsln m) + (TypesMustSubsumeInsideUndo csenv ndeep (WithTrace newTrace) cxsln m) + (TypesMustSubsumeOrConvertInsideUndo csenv ndeep (WithTrace newTrace) cxsln cx.IsSome m) (ArgsMustSubsumeOrConvertInsideUndo csenv ndeep newTrace cxsln cx.IsSome calledMeth) reqdRetTyOpt calledMeth) with @@ -2641,7 +2690,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 -> @@ -2691,9 +2740,15 @@ 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 + // Note: Relies on 'compare' respecting true > false + let c = compare (not usesTDC1) (not usesTDC2) + 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) @@ -2809,7 +2864,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 = @@ -2825,8 +2880,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 @@ -2849,17 +2904,19 @@ and ResolveOverloading let cxsln = Option.map (fun traitInfo -> (traitInfo, MemberConstraintSolutionOfMethInfo csenv.SolverState m calledMeth.Method calledMeth.CalledTyArgs)) cx match calledMethTrace with | NoTrace -> - return! + let! _usesTDC = // No trace available for CanMemberSigsMatchUpToCheck with ArgsMustSubsumeOrConvert CanMemberSigsMatchUpToCheck csenv permitOptArgs true (MustUnify csenv ndeep trace cxsln) - (TypesMustSubsumeOrConvertInsideUndo csenv ndeep trace cxsln m)// REVIEW: this should not be an "InsideUndo" operation + (TypesMustSubsumeInsideUndo csenv ndeep trace cxsln m)// REVIEW: this should not be an "InsideUndo" operation + (TypesMustSubsumeOrConvertInsideUndo csenv ndeep trace cxsln true m)// REVIEW: this should not be an "InsideUndo" operation (ArgsMustSubsumeOrConvert csenv ndeep trace cxsln cx.IsSome true) reqdRetTyOpt calledMeth + return () | WithTrace calledMethTrc -> // Re-play existing trace @@ -2868,16 +2925,19 @@ and ResolveOverloading // Unify return type match reqdRetTyOpt with | None -> () - | Some (MustConvertTo(reqdRetTy)) when g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion && not (isSealedTy g reqdRetTy) -> - let actualRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling - return! TypesMustSubsumeOrConvertInsideUndo csenv ndeep trace cxsln m reqdRetTy actualRetTy - | Some reqdRetTy -> - let reqdRetTy = reqdRetTy.Commit + | 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(reqdRetTy) when g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion -> + let! _usesTDC = TypesMustSubsumeOrConvertInsideUndo csenv ndeep trace cxsln true m reqdRetTy actualRetTy + return () + | _ -> + let! _usesTDC = MustUnify csenv ndeep trace cxsln reqdRetTy.Commit actualRetTy + return () + } | None -> @@ -2905,14 +2965,15 @@ 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) + (TypesMustSubsumeInsideUndo csenv ndeep NoTrace None m) + (TypesMustSubsumeOrConvertInsideUndo csenv ndeep NoTrace None false m) (ArgsMustSubsumeOrConvert csenv ndeep NoTrace None false false) // UnifyUniqueOverloading is not called in case of trait call - pass isConstraint=false (Some reqdRetTy) calledMeth @@ -2965,7 +3026,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 @@ -2976,9 +3037,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/ErrorLogger.fs b/src/fsharp/ErrorLogger.fs index 76c31771571..0d4bcbadbf7 100644 --- a/src/fsharp/ErrorLogger.fs +++ b/src/fsharp/ErrorLogger.fs @@ -546,9 +546,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 @@ -620,6 +620,7 @@ 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 AtLeastOne2D f xs ys = List.zip xs ys |> AtLeastOneD (fun (x,y) -> f x y) [] module OperationResult = diff --git a/src/fsharp/ErrorLogger.fsi b/src/fsharp/ErrorLogger.fsi index ec2e9340635..df0ea5957a8 100644 --- a/src/fsharp/ErrorLogger.fsi +++ b/src/fsharp/ErrorLogger.fsi @@ -259,7 +259,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> @@ -307,6 +307,8 @@ val RepeatWhileD: nDeep:int -> body:(int -> OperationResult) -> OperationR val AtLeastOneD: f:('a -> OperationResult) -> l:'a list -> OperationResult +val AtLeastOne2D: f:('a -> 'b -> OperationResult) -> xs:'a list -> ys:'b list -> OperationResult + module OperationResult = val inline ignore: res:OperationResult<'a> -> OperationResult diff --git a/src/fsharp/MethodCalls.fs b/src/fsharp/MethodCalls.fs index e5c9e5b88be..0edc6e79cd7 100644 --- a/src/fsharp/MethodCalls.fs +++ b/src/fsharp/MethodCalls.fs @@ -139,38 +139,60 @@ type CallerArgs<'T> = // Callsite conversions //------------------------------------------------------------------------- +let AdjustDelegateTy (infoReader: InfoReader) actualTy reqdTy m = + let g = infoReader.g + 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 AdjustRequiredTypeForTypeDirectedConversions (infoReader: InfoReader) isConstraint (reqdTy: TType) actualTy m = + let g = infoReader.g + + if isConstraint then + reqdTy, false + else + + if isDelegateTy g reqdTy && isFunTy g actualTy then + AdjustDelegateTy infoReader actualTy reqdTy m, true + + // Adhoc int32 --> int64 + elif typeEquiv g g.int64_ty reqdTy && typeEquiv g g.int32_ty actualTy then + g.int32_ty, true + // Adhoc int32 --> float32 + elif typeEquiv g g.float32_ty reqdTy && typeEquiv g g.int32_ty actualTy then + g.int32_ty, true + // Adhoc int32 --> float64 + elif typeEquiv g g.float_ty reqdTy && typeEquiv g g.int32_ty actualTy then + g.int32_ty, true + else reqdTy, false + // 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 AdjustCalledArgTypeForTypeDirectedConversionsAndLinqExpressionsAndAutoQuote (infoReader: InfoReader) (callerArgTy: TType) (calledArg: CalledArg) m = let g = infoReader.g let calledArgTy = calledArg.CalledArgumentType - 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 + AdjustRequiredTypeForTypeDirectedConversions infoReader false calledArgTy callerArgTy m elif isLinqExpressionTy g calledArgTy && isFunTy g callerArgTy then let calledArgTyNoExpr = destLinqExpressionTy g calledArgTy - if isDelegateTy g calledArgTyNoExpr then - adjustDelegateTy calledArgTyNoExpr - else - calledArgTy + AdjustRequiredTypeForTypeDirectedConversions infoReader false calledArgTyNoExpr callerArgTy m elif calledArg.ReflArgInfo.AutoQuote && isQuotedExprTy g calledArgTy && not (isQuotedExprTy g callerArgTy) then - destQuotedExprTy g calledArgTy + destQuotedExprTy g calledArgTy, true - else calledArgTy + else + AdjustRequiredTypeForTypeDirectedConversions infoReader 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) enforceNullableOptionalsKnownTypes (calledArg: CalledArg) calledArgTy (callerArg: CallerArg<_>) = + let g = infoReader.g + let m = callerArg.Range if callerArg.IsExplicitOptional then match calledArg.OptArgInfo with @@ -178,25 +200,26 @@ let AdjustCalledArgTypeForOptionals (g: TcGlobals) enforceNullableOptionalsKnown | CallerSide _ -> if g.langVersion.SupportsFeature LanguageFeature.NullableOptionalInterop then if isNullableTy g calledArgTy then - mkOptionTy g (destNullableTy g calledArgTy) + mkOptionTy g (destNullableTy g calledArgTy), false else - mkOptionTy g calledArgTy + mkOptionTy g calledArgTy, false else - calledArgTy + calledArgTy, false // FSharpMethod(?x = arg), optional F#-style argument | CalleeSide -> // In this case, the called argument will already have option type - calledArgTy + calledArgTy, false | NotOptional -> // This condition represents an error but the error is raised in later processing - calledArgTy + calledArgTy, false else + let callerArgTy = callerArg.CallerArgumentType 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 + calledArgTy, false // The arg should have type ty. However for backwards compat, we also allow arg to have type Nullable | NotOptional @@ -204,33 +227,39 @@ 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, false // 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 false calledArgTy2 callerArgTy m + // If neither and we are at the end of overload resolution then use the Nullable elif enforceNullableOptionalsKnownTypes then - calledArgTy + calledArgTy, false + // If at the beginning of inference then use a type variable. else let destTy = destNullableTy g calledArgTy match calledArg.OptArgInfo with // Use the type variable from the Nullable if called arg is not optional. | NotOptional when isTyparTy g destTy -> - destTy + destTy, false | _ -> let compgenId = mkSynId range0 unassignedTyparName - mkTyparTy (Construct.NewTypar (TyparKind.Type, TyparRigidity.Flexible, Typar(compgenId, NoStaticReq, true), false, TyparDynamicReq.No, [], false, false)) + let tp = mkTyparTy (Construct.NewTypar (TyparKind.Type, TyparRigidity.Flexible, Typar(compgenId, NoStaticReq, true), false, TyparDynamicReq.No, [], false, false)) + tp, false else - calledArgTy + AdjustRequiredTypeForTypeDirectedConversions infoReader false calledArgTy callerArgTy 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 + AdjustRequiredTypeForTypeDirectedConversions infoReader false calledArgTy2 callerArgTy m // F# supports three adhoc conversions at method callsites (note C# supports more, though ones // such as implicit conversions interact badly with type inference). @@ -258,7 +287,7 @@ let AdjustCalledArgType (infoReader: InfoReader) isConstraint enforceNullableOpt let calledArgTy = calledArg.CalledArgumentType let callerArgTy = callerArg.CallerArgumentType if isConstraint then - calledArgTy + calledArgTy, false else // If the called method argument is an inref type, then the caller may provide a byref or value @@ -269,20 +298,23 @@ let AdjustCalledArgType (infoReader: InfoReader) isConstraint enforceNullableOpt else destByrefTy g calledArgTy #else - calledArgTy + calledArgTy, false #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, false else - mkRefCellTy g (destByrefTy g calledArgTy) + mkRefCellTy g (destByrefTy g calledArgTy), false else - let calledArgTy2 = AdjustCalledArgTypeForLinqExpressionsAndAutoQuote infoReader callerArgTy calledArg m - let calledArgTy3 = AdjustCalledArgTypeForOptionals g enforceNullableOptionalsKnownTypes calledArg calledArgTy2 callerArg - calledArgTy3 + // TODO: consider interaction with optional arguments + // We should swap the order of these calls, first stripping the optionality + // then making the type directed conversion + let calledArgTy2, usesTDC = AdjustCalledArgTypeForTypeDirectedConversionsAndLinqExpressionsAndAutoQuote infoReader callerArgTy calledArg m + let calledArgTy3, usesTDC2 = AdjustCalledArgTypeForOptionals infoReader enforceNullableOptionalsKnownTypes calledArg calledArgTy2 callerArg + calledArgTy3, usesTDC || usesTDC2 //------------------------------------------------------------------------- // CalledMeth @@ -640,7 +672,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, _usesTDC = AdjustCalledArgType infoReader false false arg.CalledArg arg.CallerArg if countOfCallerLambdaArg > 0 then // Decompose the explicit function type of the target let calledLambdaArgTys, _calledLambdaRetTy = stripFunTy g adjustedCalledArgTy @@ -1015,7 +1047,25 @@ 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 AdjustExprForTypeDirectedConversions (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 + // Adhoc int32 --> int64 + elif g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion && typeEquiv g g.int64_ty reqdTy && typeEquiv g g.int32_ty actualTy then + mkCallToInt64Operator g m actualTy expr + // Adhoc int32 --> float32 + elif g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion && typeEquiv g g.float32_ty reqdTy && typeEquiv g g.int32_ty actualTy then + mkCallToSingleOperator g m actualTy expr + // Adhoc int32 --> float64 + elif g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion && typeEquiv g g.float_ty reqdTy && typeEquiv g g.int32_ty actualTy then + mkCallToDoubleOperator g m actualTy expr + // TODO: consider op_Implicit + // TODO: consider Nullable + else + mkCoerceIfNeeded g reqdTy actualTy expr + +// Handle adhoc argument conversions +let AdjustCallerArgExpr (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) @@ -1025,9 +1075,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 @@ -1046,9 +1093,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 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 @@ -1167,11 +1214,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 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) -> @@ -1195,7 +1245,9 @@ 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 + let calledNonOptTy = destNullableTy g calledArgTy + let _, callerArgExpr2 = AdjustCallerArgExpr g amap infoReader ad isOutArg calledNonOptTy reflArgInfo callerArgTy m callerArgExpr + MakeNullableExprIfNeeded infoReader calledArgTy callerArgTy callerArgExpr2 m else failwith "unreachable" // see case above @@ -1221,21 +1273,24 @@ let AdjustCallerArgForOptional tcFieldInit eCallerMemberName (infoReader: InfoRe // 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 + let calledNonOptTy = destNullableTy g calledArgTy + let _, callerArgExpr2 = AdjustCallerArgExpr 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 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 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 @@ -1262,7 +1317,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 tcFieldInit eCallerMemberName (infoReader: InfoReader) ad (calledMeth: CalledMeth<_>) mItem mMethExpr = let g = infoReader.g let assignedNamedArgs = calledMeth.ArgSets |> List.collect (fun argSet -> argSet.AssignedNamedArgs) @@ -1279,8 +1334,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 tcFieldInit eCallerMemberName infoReader ad) unnamedArgs + let adjustedAssignedNamedArgs = List.map (AdjustCallerArgForOptional tcFieldInit eCallerMemberName infoReader ad) assignedNamedArgs optArgs, optArgPreBinder, adjustedNormalUnnamedArgs, adjustedAssignedNamedArgs @@ -1313,7 +1368,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 g amap infoReader ad isOutArg paramArrayCalledArgElementType paramArrayCalledArg.ReflArgInfo callerArgTy m callerArgExpr) |> List.unzip let paramArrayExpr = Expr.Op (TOp.Array, [paramArrayCalledArgElementType], paramArrayExprs, mMethExpr) @@ -1350,7 +1405,7 @@ let AdjustCallerArgs tcFieldInit eCallerMemberName (infoReader: InfoReader) ad ( AdjustParamArrayCallerArgs g amap infoReader ad calledMeth mMethExpr let optArgs, optArgPreBinder, adjustedNormalUnnamedArgs, adjustedFinalAssignedNamedArgs = - AdjustCallerArgsForOptionals tcFieldInit eCallerMemberName infoReader calledMeth mItem mMethExpr + AdjustCallerArgsForOptionals tcFieldInit eCallerMemberName infoReader ad calledMeth mItem mMethExpr let outArgs, outArgExprs, outArgTmpBinds = AdjustOutCallerArgs g calledMeth mMethExpr @@ -1373,7 +1428,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 g amap infoReader ad isOutArg calledArgTy reflArgInfo callerArgTy m e) |> List.unzip objArgPreBinder, objArgs, allArgsPreBinders, allArgs, allArgsCoerced, optArgPreBinder, paramArrayPreBinders, outArgExprs, outArgTmpBinds diff --git a/src/fsharp/MethodCalls.fsi b/src/fsharp/MethodCalls.fsi index 5965d85bcc3..34d459fbe93 100644 --- a/src/fsharp/MethodCalls.fsi +++ b/src/fsharp/MethodCalls.fsi @@ -98,7 +98,10 @@ type CallerArgs<'T> = 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 +val AdjustCalledArgType: infoReader:InfoReader -> isConstraint:bool -> enforceNullableOptionalsKnownTypes:bool -> calledArg:CalledArg -> callerArg:CallerArg<'a> -> TType * bool + +/// F# supports some adhoc conversions to make expression fit known overall type +val AdjustRequiredTypeForTypeDirectedConversions: infoReader:InfoReader -> isConstraint:bool -> reqdTy: TType -> actualTy:TType -> m: range -> TType * bool type CalledMethArgSet<'T> = { /// The called arguments corresponding to "unnamed" arguments @@ -143,13 +146,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 @@ -157,8 +168,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 @@ -184,21 +198,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 @@ -209,8 +236,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 @@ -262,7 +292,9 @@ 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: g: TcGlobals -> amap:ImportMap -> infoReader:InfoReader -> ad:AccessorDomain -> reqdTy:TType -> actualTy:TType -> m:range -> expr:Expr -> Expr + +val AdjustCallerArgExpr: 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 diff --git a/tests/fsharp/core/auto-widen/auto-widen.fsx b/tests/fsharp/core/auto-widen/auto-widen.fsx new file mode 100644 index 00000000000..9f7493d3069 --- /dev/null +++ b/tests/fsharp/core/auto-widen/auto-widen.fsx @@ -0,0 +1,223 @@ +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) } + +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) = 1 + let x = C.M1(2L) + +module Overloads3 = + type C() = + static member M1(x:string) = failwith "nope" + static member M1(x:int64) = 1 + let x = C.M1(2) + +module OverloadedOptionals1 = + type C() = + static member M1(x:string) = failwith "nope" + static member M1(?x:int64) = 1 + let x = C.M1(x=2) + +module OverloadedOptionals2 = + type C() = + static member M1(?x:int) = 1 + 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) = 1 + 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) + +let annotations = + let _ : obj = (1,2) + let _ : obj * obj = (1,2) + + // structure through let + let _ : (obj * obj) = (let x = 1 in let y = 2 in (x,y)) + + // structure through let rec + let _ : (obj * obj) = (let rec f x = x in (3,4.0)) + + // structure through sequence + let _ : (obj * obj) = (); (3,4.0) + + // struct tuple + let _ : struct (obj * obj) = struct (1,2) + + // record (both field and overall result) + // let _ : obj = { F1 = (1, 2) } // TODO + + // record (both field and overall result) + { F1 = (1, 2uy) }.F1 <- (3.0, 4) + + // anon record + let _ : {| A: obj |} = {| A = 1 |} + + // lambda return + let _ : (unit -> obj) = (fun () -> 1) + + // function lambda return + let _ : (int -> obj) = (function 1 -> 1 | 2 -> 3.0 | _ -> 4uy) + + let _ : (unit -> obj * obj) = (fun () -> (1,2)) + + // constants + (1 :> System.IComparable) |> ignore + + let _ : System.IComparable = 1 + + // array constants + let _ : System.Array = [| 1us |] + + let _ : System.Array = [| 1I |] + + let _ : System.IComparable = 1I + + // property + let _ : System.IComparable = System.String.Empty + + // method + let _ : System.IComparable = System.String.Format("") + + let _ : obj = System.String.Format("") + + let _ : System.IComparable = System.String.Format("") + + // array constants + + let _ : obj[] = [| 1 |] + let _ : (obj * obj)[] = [| (1,1) |] + let _ : (obj * obj)[] = [| ("abc",1) |] + let _ : (string * obj)[] = [| ("abc",1) |] + let _ : (string * obj)[] = [| ("abc",1); ("abc",3.0) |] + let _ : (string * obj)[] = [| Unchecked.defaultof<_>; ("abc",3.0) |] + let _ : struct (string * obj)[] = [| Unchecked.defaultof<_>; struct ("abc",3.0) |] + + let _ : obj = 1 + let _ : obj = (1 : int) + let _ : obj = "" + let _ : obj = ("" : string) + let _ : obj = ("" : System.IComparable) + let _ : obj = ("" : _) + let _ : obj = ("" : obj) + let _ : obj = { new System.ICloneable with member x.Clone() = obj() } + let _ : obj = "" + let _ : obj = string "" + let _ : obj = id "" + + // conditional + let _ : obj = if true then 1 else 3.0 + let _ : obj = (if true then 1 else 3.0) + let _ : obj = (if true then 1 elif true then 2uy else 3.0) + + // try-with + let _ : obj = try 1 with _ -> 3.0 + + // try-finally + let _ : obj = try 1 finally () + + // match + let _ : obj = match true with true -> 1 | _ -> 3.0 + () + +let f1 () : obj = 1 +let f2 () : obj = if true then 1 else 3.0 + +#if NEGATIVE +let annotations = + (id "" : obj) |> ignore /// note, the 'obj' annotation correctly instantiates the type variable to 'obj' + ((if true then ()) : obj) |> ignore + +let f3 x = if true then 1 else 3.0 +#endif + +printfn "test done" \ No newline at end of file From 3c0bb247b0fcd66bb5e3e74a92c9474109e797a6 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 26 Jan 2021 15:55:25 +0000 Subject: [PATCH 19/42] op_Implicit support --- src/fsharp/CheckExpressions.fs | 49 +- src/fsharp/CompilerDiagnostics.fs | 1 + src/fsharp/ConstraintSolver.fs | 213 ++++--- src/fsharp/ErrorLogger.fs | 9 +- src/fsharp/ErrorLogger.fsi | 8 +- src/fsharp/FSComp.txt | 4 +- src/fsharp/LanguageFeatures.fs | 6 +- src/fsharp/LanguageFeatures.fsi | 2 +- src/fsharp/MethodCalls.fs | 257 +++++--- src/fsharp/MethodCalls.fsi | 76 ++- src/fsharp/xlf/FSComp.txt.cs.xlf | 20 +- src/fsharp/xlf/FSComp.txt.de.xlf | 20 +- src/fsharp/xlf/FSComp.txt.es.xlf | 20 +- src/fsharp/xlf/FSComp.txt.fr.xlf | 20 +- src/fsharp/xlf/FSComp.txt.it.xlf | 20 +- src/fsharp/xlf/FSComp.txt.ja.xlf | 20 +- src/fsharp/xlf/FSComp.txt.ko.xlf | 20 +- src/fsharp/xlf/FSComp.txt.pl.xlf | 20 +- src/fsharp/xlf/FSComp.txt.pt-BR.xlf | 20 +- src/fsharp/xlf/FSComp.txt.ru.xlf | 20 +- src/fsharp/xlf/FSComp.txt.tr.xlf | 20 +- src/fsharp/xlf/FSComp.txt.zh-Hans.xlf | 20 +- src/fsharp/xlf/FSComp.txt.zh-Hant.xlf | 20 +- tests/fsharp/core/access/test.fsx | 1 - tests/fsharp/core/auto-widen/5.0/test.bsl | 591 ++++++++++++++++++ .../{auto-widen.fsx => 5.0/test.fsx} | 75 ++- tests/fsharp/core/auto-widen/preview/test.bsl | 4 + tests/fsharp/core/auto-widen/preview/test.fsx | 303 +++++++++ tests/fsharp/tests.fs | 51 +- 29 files changed, 1617 insertions(+), 293 deletions(-) create mode 100644 tests/fsharp/core/auto-widen/5.0/test.bsl rename tests/fsharp/core/auto-widen/{auto-widen.fsx => 5.0/test.fsx} (76%) create mode 100644 tests/fsharp/core/auto-widen/preview/test.bsl create mode 100644 tests/fsharp/core/auto-widen/preview/test.fsx diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index c35a4d8d66f..7d67e913470 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -457,14 +457,22 @@ let UnifyTypes cenv (env: TcEnv) m actualTy expectedTy = // then allow subsumption. let UnifyOverallType cenv (env: TcEnv) m overallTy actualTy = match overallTy with - | MustConvertTo(reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion -> + | MustConvertTo(reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions -> 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 = AdjustRequiredTypeForTypeDirectedConversions cenv.infoReader false reqdTy actualTy m + let reqdTy2, usesTDC, eqn = AdjustRequiredTypeForTypeDirectedConversions cenv.infoReader env.eAccessRights 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 () else @@ -5444,7 +5452,7 @@ and TcExprUndelayedNoType cenv env tpenv synExpr: Expr * TType * _ = and TcExprLeafProtectExcept2 p cenv (overallTy: OverallTy) actualTy (env: TcEnv) canAdhoc m f = match overallTy with - | MustConvertTo(reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion && not (p reqdTy) -> + | MustConvertTo(reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && not (p reqdTy) -> // Note about the cases where canAdhoc=false: // Some constructs (list expressions etc) require placing the subtype constraint down // before processing in order to propagate into the construct. @@ -5461,9 +5469,18 @@ and TcExprLeafProtectExcept2 p cenv (overallTy: OverallTy) actualTy (env: TcEnv) AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace reqdTy actualTy let expr, tpenv = f () if canAdhoc then - let reqdTy2, _usesTDC = AdjustRequiredTypeForTypeDirectedConversions cenv.infoReader false reqdTy actualTy m + let reqdTy2, usesTDC, eqn = AdjustRequiredTypeForTypeDirectedConversions cenv.infoReader env.eAccessRights 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 -> () AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace reqdTy2 actualTy - let expr2 = AdjustExprForTypeDirectedConversions cenv.g cenv.amap cenv.infoReader env.AccessRights reqdTy actualTy m expr + let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g + let expr2 = AdjustExprForTypeDirectedConversions tcVal cenv.g cenv.amap cenv.infoReader env.AccessRights reqdTy actualTy m expr expr2, tpenv | _ -> UnifyTypes cenv env m overallTy.Commit actualTy @@ -5471,7 +5488,7 @@ and TcExprLeafProtectExcept2 p cenv (overallTy: OverallTy) actualTy (env: TcEnv) and TcExprLeafProtectExcept p cenv (overallTy: OverallTy) (env: TcEnv) canAdhoc m f = match overallTy with - | MustConvertTo(reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion && not (p reqdTy) -> + | MustConvertTo(reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && not (p reqdTy) -> let actualTy = NewInferenceType() TcExprLeafProtectExcept2 p cenv overallTy actualTy env canAdhoc m (fun () -> f actualTy) | _ -> @@ -5559,7 +5576,8 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = // (1 : obj) //let overallTyInner = (* if isFromReturnAnnotation then *) MustConvertTo tgtTy (* else MustEqual tgtTy *) let bodyExpr, tpenv = TcExpr cenv (MustConvertTo tgtTy) env tpenv synBodyExpr - let bodyExpr2 = AdjustExprForTypeDirectedConversions cenv.g cenv.amap cenv.infoReader env.AccessRights overallTy.Commit tgtTy m bodyExpr + let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g + let bodyExpr2 = AdjustExprForTypeDirectedConversions tcVal cenv.g cenv.amap cenv.infoReader env.AccessRights overallTy.Commit tgtTy m bodyExpr bodyExpr2, tpenv // e :? ty @@ -7460,7 +7478,8 @@ and TcDelayed cenv (overallTy: OverallTy) env tpenv mExpr expr exprty (atomicFla | DelayedDot :: _ -> // at the end of the application chain allow coercion introduction UnifyOverallTypeAndRecover cenv env mExpr overallTy exprty - let expr2 = AdjustExprForTypeDirectedConversions cenv.g cenv.amap cenv.infoReader env.AccessRights overallTy.Commit exprty mExpr expr.Expr + let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g + let expr2 = AdjustExprForTypeDirectedConversions tcVal cenv.g cenv.amap cenv.infoReader env.AccessRights overallTy.Commit exprty mExpr expr.Expr expr2, tpenv // Expr.M (args) where x.M is a .NET method or index property @@ -8814,7 +8833,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 @@ -8949,7 +8968,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 -> @@ -9059,7 +9079,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 = MethodCalls.AdjustCallerArgExpr 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]) @@ -9068,7 +9089,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 = MethodCalls.AdjustCallerArgExpr 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 @@ -9076,7 +9098,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 = MethodCalls.AdjustCallerArgExpr 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 diff --git a/src/fsharp/CompilerDiagnostics.fs b/src/fsharp/CompilerDiagnostics.fs index fd69be1fea0..fd1db2ebf14 100644 --- a/src/fsharp/CompilerDiagnostics.fs +++ b/src/fsharp/CompilerDiagnostics.fs @@ -379,6 +379,7 @@ let warningOn err level specificWarnOn = match n with | 1182 -> false // chkUnusedValue - off by default | 3180 -> false // abImplicitHeapAllocation - off by default + | 3386 -> false // tcImplicitConversionUsed - 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 783de7649b6..75f86efbaa7 100644 --- a/src/fsharp/ConstraintSolver.fs +++ b/src/fsharp/ConstraintSolver.fs @@ -2252,12 +2252,12 @@ and CanMemberSigsMatchUpToCheck (csenv: ConstraintSolverEnv) permitOptArgs // are we allowed to supply optional and/or "param" arguments? alwaysCheckReturn // always check the return type? - (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 + (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 = + (calledMeth: CalledMeth<_>): OperationResult = trackErrors { let g = csenv.g let amap = csenv.amap @@ -2275,7 +2275,7 @@ and CanMemberSigsMatchUpToCheck if minst.Length <> uminst.Length then return! ErrorD(Error(FSComp.SR.csTypeInstantiationLengthMismatch(), m)) else - let! usesTDC1 = AtLeastOne2D unifyTypes minst uminst + let! usesTDC1 = MapCombineTDC2D unifyTypes minst uminst let! usesTDC2 = trackErrors { if not (permitOptArgs || isNil unnamedCalledOptArgs) then @@ -2291,15 +2291,15 @@ and CanMemberSigsMatchUpToCheck else return! ErrorD(Error (FSComp.SR.csMemberIsNotInstance(minfo.LogicalName), m)) else - return! AtLeastOne2D subsumeTypes calledObjArgTys callerObjArgTys + return! MapCombineTDC2D subsumeTypes calledObjArgTys callerObjArgTys } let! usesTDC3 = - calledMeth.ArgSets |> AtLeastOneD (fun argSet -> trackErrors { + calledMeth.ArgSets |> MapCombineTDCD (fun argSet -> trackErrors { if argSet.UnnamedCalledArgs.Length <> argSet.UnnamedCallerArgs.Length then return! ErrorD(Error(FSComp.SR.csArgumentLengthMismatch(), m)) else - return! AtLeastOne2D subsumeOrConvertArg argSet.UnnamedCalledArgs argSet.UnnamedCallerArgs + return! MapCombineTDC2D subsumeOrConvertArg argSet.UnnamedCalledArgs argSet.UnnamedCallerArgs }) let! usesTDC4 = @@ -2310,20 +2310,25 @@ and CanMemberSigsMatchUpToCheck let reflArgInfo = calledArg.ReflArgInfo // propagate the reflected-arg info to each param array argument match calledMeth.ParamArrayCallerArgs with | Some args -> - args |> AtLeastOneD (fun callerArg -> - subsumeOrConvertArg (CalledArg((0, 0), false, NotOptional, NoCallerInfo, false, false, None, reflArgInfo, paramArrayElemTy)) callerArg) - | _ -> ResultD false + args |> MapCombineTDCD (fun callerArg -> + subsumeOrConvertArg (CalledArg((0, 0), false, NotOptional, NoCallerInfo, false, false, None, reflArgInfo, paramArrayElemTy)) callerArg + ) + + + | _ -> ResultD TypeDirectedConversionUsed.No else - ResultD false - | _ -> ResultD false + ResultD TypeDirectedConversionUsed.No + | _ -> ResultD TypeDirectedConversionUsed.No let! usesTDC5 = - calledMeth.ArgSets |> AtLeastOneD (fun argSet -> - argSet.AssignedNamedArgs |> AtLeastOneD (fun arg -> - subsumeOrConvertArg arg.CalledArg arg.CallerArg)) + calledMeth.ArgSets |> MapCombineTDCD (fun argSet -> + argSet.AssignedNamedArgs |> MapCombineTDCD (fun arg -> + subsumeOrConvertArg arg.CalledArg arg.CallerArg + ) + ) let! usesTDC6 = - assignedItemSetters |> AtLeastOneD (fun (AssignedItemSetter(_, item, caller)) -> + assignedItemSetters |> MapCombineTDCD (fun (AssignedItemSetter(_, item, caller)) -> let name, calledArgTy = match item with | AssignedPropSetter(_, pminfo, pminst) -> @@ -2339,7 +2344,8 @@ and CanMemberSigsMatchUpToCheck let calledArgTy = rfinfo.FieldType rfinfo.Name, calledArgTy - subsumeOrConvertArg (CalledArg((-1, 0), false, NotOptional, NoCallerInfo, false, false, Some (mkSynId m name), ReflectedArgInfo.None, calledArgTy)) caller) + 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 @@ -2347,17 +2353,17 @@ and CanMemberSigsMatchUpToCheck // - Never take into account return type information for constructors let! usesTDC7 = match reqdRetTyOpt with - | Some _ when ( (* minfo.IsConstructor || *) not alwaysCheckReturn && isNil unnamedCalledOutArgs) -> ResultD false - | Some (MustConvertTo(reqdTy)) when g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion -> + | Some _ when ( (* minfo.IsConstructor || *) not alwaysCheckReturn && isNil unnamedCalledOutArgs) -> + ResultD TypeDirectedConversionUsed.No + | Some (MustConvertTo(reqdTy)) when g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions -> let methodRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling subsumeOrConvertTypes reqdTy methodRetTy | Some reqdRetTy -> let methodRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling unifyTypes reqdRetTy.Commit methodRetTy | _ -> - ResultD false - return usesTDC1 || usesTDC2 || usesTDC3 || usesTDC4 || usesTDC5 || usesTDC6 || usesTDC7 - + 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 @@ -2392,6 +2398,7 @@ and private SolveTypeEqualsTypeWithReport (csenv: ConstraintSolverEnv) ndeep m and ArgsMustSubsumeOrConvert (csenv: ConstraintSolverEnv) + ad ndeep trace cxsln @@ -2402,7 +2409,15 @@ and ArgsMustSubsumeOrConvert let g = csenv.g let m = callerArg.Range - let calledArgTy, usesTDC = 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)) @@ -2410,41 +2425,74 @@ and ArgsMustSubsumeOrConvert return usesTDC } -and MustUnify csenv ndeep trace cxsln ty1 ty2 = - trackErrors { - do! SolveTypeEqualsTypeWithReport csenv ndeep csenv.m trace cxsln ty1 ty2 - return false - } - -and MustUnifyInsideUndo csenv ndeep 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 { - do! SolveTypeEqualsTypeWithReport csenv ndeep csenv.m (WithTrace trace) cxsln ty1 ty2 - return false + 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 ArgsMustSubsumeOrConvertInsideUndo (csenv: ConstraintSolverEnv) ndeep trace cxsln isConstraint calledMeth calledArg (CallerArg(callerArgTy, m, _, _) as callerArg) = +and TypesEquiv csenv ndeep trace cxsln ty1 ty2 = trackErrors { - let calledArgTy, usesTDC = AdjustCalledArgType csenv.InfoReader isConstraint true calledArg callerArg - do! SolveTypeSubsumesTypeWithWrappedContextualReport csenv ndeep m (WithTrace trace) cxsln calledArgTy callerArgTy (fun e -> ArgDoesNotMatchError(e :?> _, calledMeth, calledArg, callerArg)) - return usesTDC + do! SolveTypeEqualsTypeWithReport csenv ndeep csenv.m trace cxsln ty1 ty2 + return TypeDirectedConversionUsed.No } -and TypesMustSubsumeInsideUndo (csenv: ConstraintSolverEnv) ndeep trace cxsln m calledArgTy callerArgTy = +and TypesMustSubsume (csenv: ConstraintSolverEnv) ndeep trace cxsln m calledArgTy callerArgTy = trackErrors { do! SolveTypeSubsumesTypeWithReport csenv ndeep m trace cxsln calledArgTy callerArgTy - return false + return TypeDirectedConversionUsed.No } -and TypesMustSubsumeOrConvertInsideUndo (csenv: ConstraintSolverEnv) ndeep trace cxsln isConstraint m reqdTy actualTy = +and TypesMustSubsumeOrConvert (csenv: ConstraintSolverEnv) ad ndeep trace cxsln isConstraint m reqdTy actualTy = trackErrors { - let reqdTy, usesTDC = AdjustRequiredTypeForTypeDirectedConversions csenv.InfoReader isConstraint reqdTy actualTy m + let reqdTy, usesTDC, eqn = AdjustRequiredTypeForTypeDirectedConversions csenv.InfoReader ad 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 ArgsEquivOrConvertInsideUndo (csenv: ConstraintSolverEnv) isConstraint calledArg (CallerArg(callerArgTy, m, _, _) as callerArg) = +and ArgsEquivOrConvert (csenv: ConstraintSolverEnv) ad ndeep trace cxsln isConstraint calledArg (callerArg: CallerArg<_>) = trackErrors { - let calledArgTy, usesTDC = AdjustCalledArgType csenv.InfoReader isConstraint true calledArg callerArg + 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 @@ -2616,37 +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) - (TypesMustSubsumeInsideUndo csenv ndeep (WithTrace newTrace) cxsln m) - (TypesMustSubsumeOrConvertInsideUndo csenv ndeep (WithTrace newTrace) cxsln cx.IsSome m) - (ArgsEquivOrConvertInsideUndo csenv cx.IsSome) + (TypesEquiv csenv ndeep (WithTrace newTrace) cxsln) // instantiations equivalent + (TypesMustSubsume csenv ndeep (WithTrace newTrace) cxsln m) // obj can subsume + (TypesMustSubsumeOrConvert 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) + + match exactMatchCandidates with | [(calledMeth, warns, _, _usesTDC)] -> - Some calledMeth, OkResult (warns, ()), NoTrace // Can't re-play the trace since ArgsEquivOrConvertInsideUndo was used + 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) - (TypesMustSubsumeInsideUndo csenv ndeep (WithTrace newTrace) cxsln m) - (TypesMustSubsumeOrConvertInsideUndo csenv ndeep (WithTrace newTrace) cxsln cx.IsSome 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 + (TypesMustSubsumeOrConvert 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 @@ -2678,10 +2730,10 @@ and ResolveOverloading csenv permitOptArgs alwaysCheckReturn - (MustUnifyInsideUndo csenv ndeep newTrace cxsln) - (TypesMustSubsumeInsideUndo csenv ndeep (WithTrace newTrace) cxsln m) - (TypesMustSubsumeOrConvertInsideUndo csenv ndeep (WithTrace newTrace) cxsln cx.IsSome m) - (ArgsMustSubsumeOrConvertInsideUndo csenv ndeep newTrace cxsln cx.IsSome calledMeth) + (TypesEquiv csenv ndeep (WithTrace newTrace) cxsln) + (TypesMustSubsume csenv ndeep (WithTrace newTrace) cxsln m) + (TypesMustSubsumeOrConvert csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome m) + (ArgsMustSubsumeOrConvertWithContextualReport csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome calledMeth) reqdRetTyOpt calledMeth) with | OkResult _ -> None @@ -2746,7 +2798,7 @@ and ResolveOverloading // Prefer methods that don't use type-directed conversion // Note: Relies on 'compare' respecting true > false - let c = compare (not usesTDC1) (not usesTDC2) + 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 @@ -2905,15 +2957,14 @@ and ResolveOverloading match calledMethTrace with | NoTrace -> let! _usesTDC = - // No trace available for CanMemberSigsMatchUpToCheck with ArgsMustSubsumeOrConvert CanMemberSigsMatchUpToCheck csenv permitOptArgs true - (MustUnify csenv ndeep trace cxsln) - (TypesMustSubsumeInsideUndo csenv ndeep trace cxsln m)// REVIEW: this should not be an "InsideUndo" operation - (TypesMustSubsumeOrConvertInsideUndo csenv ndeep trace cxsln true 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 + (TypesMustSubsumeOrConvert 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 () @@ -2931,11 +2982,11 @@ and ResolveOverloading return! ErrorD(Error(FSComp.SR.tcByrefReturnImplicitlyDereferenced(), m)) else match reqdRetTy with - | MustConvertTo(reqdRetTy) when g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion -> - let! _usesTDC = TypesMustSubsumeOrConvertInsideUndo csenv ndeep trace cxsln true m reqdRetTy actualRetTy + | MustConvertTo(reqdRetTy) when g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions -> + let! _usesTDC = TypesMustSubsumeOrConvert csenv ad ndeep trace cxsln true m reqdRetTy actualRetTy return () | _ -> - let! _usesTDC = MustUnify csenv ndeep trace cxsln reqdRetTy.Commit actualRetTy + let! _usesTDC = TypesEquiv csenv ndeep trace cxsln reqdRetTy.Commit actualRetTy return () } @@ -2971,10 +3022,10 @@ let UnifyUniqueOverloading csenv true // permitOptArgs true // always check return type - (MustUnify csenv ndeep NoTrace None) - (TypesMustSubsumeInsideUndo csenv ndeep NoTrace None m) - (TypesMustSubsumeOrConvertInsideUndo csenv ndeep NoTrace None false 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) + (TypesMustSubsumeOrConvert csenv ad ndeep NoTrace None false m) + (ArgsMustSubsumeOrConvert csenv ad ndeep NoTrace None false false) (Some reqdRetTy) calledMeth return true diff --git a/src/fsharp/ErrorLogger.fs b/src/fsharp/ErrorLogger.fs index 0d4bcbadbf7..9afb31c854f 100644 --- a/src/fsharp/ErrorLogger.fs +++ b/src/fsharp/ErrorLogger.fs @@ -618,9 +618,14 @@ let TryD f g = | res -> res 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 AtLeastOne2D f xs ys = List.zip xs ys |> AtLeastOneD (fun (x,y) -> f x y) +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 df0ea5957a8..5c17050e01e 100644 --- a/src/fsharp/ErrorLogger.fsi +++ b/src/fsharp/ErrorLogger.fsi @@ -305,9 +305,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 AtLeastOne2D: f:('a -> 'b -> OperationResult) -> xs:'a list -> ys:'b 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 54837b8751e..0b6facb46de 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1521,7 +1521,7 @@ featureNullableOptionalInterop,"nullable optional interop" featureDefaultInterfaceMemberConsumption,"default interface member consumption" featureStringInterpolation,"string interpolation" featureWitnessPassing,"witness passing for trait constraints in F# quotations" -featureImplicitConversion,"implicit upcasts and other conversions for function returns, bindings and other expressions" +featureAdditionalImplicitConversions,"implicit upcasts and other conversions for function returns, bindings and other expressions" 3353,fsiInvalidDirective,"Invalid directive '#%s %s'" 3360,typrelInterfaceWithConcreteAndVariable,"'%s' cannot implement the interface '%s' with the two instantiations '%s' and '%s' because they may unify." 3361,typrelInterfaceWithConcreteAndVariableObjectExpression,"You cannot implement the interface '%s' with the two instantiations '%s' and '%s' because they may unify." @@ -1545,6 +1545,8 @@ forFormatInvalidForInterpolated4,"Interpolated strings used as type IFormattable 3382,parsEmptyFillInInterpolatedString,"Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected." 3383,lexRBraceInInterpolatedString,"A '}}' character must be escaped (by doubling) in an interpolated string." 3384,scriptSdkNotDetermined,"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. The output from '%s --version' in the directory '%s' was: '%s' and the exit code was '%d'." +3385,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'." +3386,tcImplicitConversionUsed,"This expression uses an implicit conversion to convert type '%s' to type '%s'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning." #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/LanguageFeatures.fs b/src/fsharp/LanguageFeatures.fs index 54ce4055e7f..6934954153d 100644 --- a/src/fsharp/LanguageFeatures.fs +++ b/src/fsharp/LanguageFeatures.fs @@ -32,7 +32,7 @@ type LanguageFeature = | NullableOptionalInterop | DefaultInterfaceMemberConsumption | WitnessPassing - | ImplicitConversion + | AdditionalImplicitConversions | InterfacesWithMultipleGenericInstantiation | StringInterpolation | OverloadsForCustomOperations @@ -75,7 +75,7 @@ type LanguageVersion (specifiedVersionAsString) = LanguageFeature.StringInterpolation, languageVersion50 // F# preview - LanguageFeature.ImplicitConversion, previewVersion + LanguageFeature.AdditionalImplicitConversions, previewVersion LanguageFeature.OverloadsForCustomOperations, previewVersion LanguageFeature.ExpandedMeasurables, previewVersion LanguageFeature.FromEndSlicing, previewVersion @@ -148,7 +148,7 @@ type LanguageVersion (specifiedVersionAsString) = | LanguageFeature.NullableOptionalInterop -> FSComp.SR.featureNullableOptionalInterop() | LanguageFeature.DefaultInterfaceMemberConsumption -> FSComp.SR.featureDefaultInterfaceMemberConsumption() | LanguageFeature.WitnessPassing -> FSComp.SR.featureWitnessPassing() - | LanguageFeature.ImplicitConversion -> FSComp.SR.featureImplicitConversion() + | LanguageFeature.AdditionalImplicitConversions -> 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 883f5cf6e8f..e8c30b7fbb2 100644 --- a/src/fsharp/LanguageFeatures.fsi +++ b/src/fsharp/LanguageFeatures.fsi @@ -20,7 +20,7 @@ type LanguageFeature = | NullableOptionalInterop | DefaultInterfaceMemberConsumption | WitnessPassing - | ImplicitConversion + | AdditionalImplicitConversions | InterfacesWithMultipleGenericInstantiation | StringInterpolation | OverloadsForCustomOperations diff --git a/src/fsharp/MethodCalls.fs b/src/fsharp/MethodCalls.fs index 0edc6e79cd7..6ed5ebd4776 100644 --- a/src/fsharp/MethodCalls.fs +++ b/src/fsharp/MethodCalls.fs @@ -148,78 +148,161 @@ let AdjustDelegateTy (infoReader: InfoReader) actualTy reqdTy m = else reqdTy -let AdjustRequiredTypeForTypeDirectedConversions (infoReader: InfoReader) isConstraint (reqdTy: TType) actualTy m = + +// 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. + +let TryFindRelevantImplicitConversion (infoReader: InfoReader) ad reqdTy actualTy m = + let g = infoReader.g + let amap = infoReader.amap + if g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && not (isTyparTy g actualTy) then + + 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 + + if not (isTyparTy g reqdTy2) && + not (TypeFeasiblySubsumesType 0 g amap m reqdTy2 CanCoerce actualTy) then + let implicits = + TryFindIntrinsicMethInfo infoReader m ad "op_Implicit" reqdTy2 @ + TryFindIntrinsicMethInfo infoReader m ad "op_Implicit" actualTy + 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 + errorR(Error(FSComp.SR.tcAmbiguousImplicitConversion(actualTyText, reqdTy2Text), m)))) + | _ -> None + else + None + else + None + +[] +type TypeDirectedConversionUsed = + | Yes of (DisplayEnv -> exn) + | No + static member Combine a b = + match a with + | Yes _ -> a + | No -> b + +let MapCombineTDCD mapper xs = + MapReduceD mapper TypeDirectedConversionUsed.No TypeDirectedConversionUsed.Combine xs + +let MapCombineTDC2D mapper xs ys = + MapReduce2D mapper TypeDirectedConversionUsed.No TypeDirectedConversionUsed.Combine xs ys + +let rec AdjustRequiredTypeForTypeDirectedConversions (infoReader: InfoReader) ad isConstraint (reqdTy: TType) actualTy m = let g = infoReader.g + let warn denv = + let reqdTyText, actualTyText, _cxs = NicePrint.minimalStringsOfTwoTypes denv reqdTy actualTy + Error(FSComp.SR.tcImplicitConversionUsed(actualTyText, reqdTyText), m) + if isConstraint then - reqdTy, false + reqdTy, TypeDirectedConversionUsed.No, None else + // Delegate --> function if isDelegateTy g reqdTy && isFunTy g actualTy then - AdjustDelegateTy infoReader actualTy reqdTy m, true + 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 isConstraint delegateTy actualTy m // Adhoc int32 --> int64 - elif typeEquiv g g.int64_ty reqdTy && typeEquiv g g.int32_ty actualTy then - g.int32_ty, true + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.int64_ty reqdTy && typeEquiv g g.int32_ty actualTy then + g.int32_ty, TypeDirectedConversionUsed.Yes(warn), None + // Adhoc int32 --> float32 - elif typeEquiv g g.float32_ty reqdTy && typeEquiv g g.int32_ty actualTy then - g.int32_ty, true + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.float32_ty reqdTy && typeEquiv g g.int32_ty actualTy then + g.int32_ty, TypeDirectedConversionUsed.Yes(warn), None + // Adhoc int32 --> float64 - elif typeEquiv g g.float_ty reqdTy && typeEquiv g g.int32_ty actualTy then - g.int32_ty, true - else reqdTy, false + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.int32_ty actualTy then + g.int32_ty, TypeDirectedConversionUsed.Yes(warn), None + + // Adhoc based on op_Implicit, perhaps returing a new equational type constraint to + // eliminate articifical constrained type variables. + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions then + match TryFindRelevantImplicitConversion infoReader ad reqdTy actualTy m with + | Some (_minfo, eqn) -> actualTy, TypeDirectedConversionUsed.Yes(warn), 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 AdjustCalledArgTypeForTypeDirectedConversionsAndLinqExpressionsAndAutoQuote (infoReader: InfoReader) (callerArgTy: TType) (calledArg: CalledArg) m = +let AdjustCalledArgTypeForTypeDirectedConversionsAndAutoQuote (infoReader: InfoReader) ad (callerArgTy: TType) calledArgTy (calledArg: CalledArg) m = let g = infoReader.g - let calledArgTy = calledArg.CalledArgumentType - - if isDelegateTy g calledArgTy && isFunTy g callerArgTy then - AdjustRequiredTypeForTypeDirectedConversions infoReader false calledArgTy callerArgTy m - - elif isLinqExpressionTy g calledArgTy && isFunTy g callerArgTy then - let calledArgTyNoExpr = destLinqExpressionTy g calledArgTy - AdjustRequiredTypeForTypeDirectedConversions infoReader false calledArgTyNoExpr callerArgTy m - - elif calledArg.ReflArgInfo.AutoQuote && isQuotedExprTy g calledArgTy && not (isQuotedExprTy g callerArgTy) then - destQuotedExprTy g calledArgTy, true + if calledArg.ReflArgInfo.AutoQuote && isQuotedExprTy g calledArgTy && not (isQuotedExprTy g callerArgTy) then + destQuotedExprTy g calledArgTy, TypeDirectedConversionUsed.No, None else - AdjustRequiredTypeForTypeDirectedConversions infoReader false calledArgTy callerArgTy m + AdjustRequiredTypeForTypeDirectedConversions infoReader ad 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 (infoReader: InfoReader) 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), false + mkOptionTy g (destNullableTy g calledArgTy), TypeDirectedConversionUsed.No, None else - mkOptionTy g calledArgTy, false + mkOptionTy g calledArgTy, TypeDirectedConversionUsed.No, None else - calledArgTy, false + calledArgTy, TypeDirectedConversionUsed.No, None // FSharpMethod(?x = arg), optional F#-style argument | CalleeSide -> // In this case, the called argument will already have option type - calledArgTy, false + calledArgTy, TypeDirectedConversionUsed.No, None | NotOptional -> // This condition represents an error but the error is raised in later processing - calledArgTy, false + AdjustCalledArgTypeForTypeDirectedConversionsAndAutoQuote infoReader ad callerArgTy calledArgTy calledArg m else - let callerArgTy = callerArg.CallerArgumentType 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, false + 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 @@ -228,15 +311,16 @@ let AdjustCalledArgTypeForOptionals (infoReader: InfoReader) enforceNullableOpti 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 callerArgTy then - calledArgTy, false + calledArgTy, TypeDirectedConversionUsed.No, None + // If inference has worked out it's a struct (e.g. an int) then use this elif isStructTy g callerArgTy then let calledArgTy2 = destNullableTy g calledArgTy - AdjustRequiredTypeForTypeDirectedConversions infoReader false calledArgTy2 callerArgTy m + AdjustRequiredTypeForTypeDirectedConversions infoReader ad false calledArgTy2 callerArgTy m // If neither and we are at the end of overload resolution then use the Nullable elif enforceNullableOptionalsKnownTypes then - calledArgTy, false + calledArgTy, TypeDirectedConversionUsed.No, None // If at the beginning of inference then use a type variable. else @@ -244,13 +328,13 @@ let AdjustCalledArgTypeForOptionals (infoReader: InfoReader) enforceNullableOpti match calledArg.OptArgInfo with // Use the type variable from the Nullable if called arg is not optional. | NotOptional when isTyparTy g destTy -> - destTy, false + destTy, TypeDirectedConversionUsed.No, None | _ -> let compgenId = mkSynId range0 unassignedTyparName let tp = mkTyparTy (Construct.NewTypar (TyparKind.Type, TyparRigidity.Flexible, Typar(compgenId, NoStaticReq, true), false, TyparDynamicReq.No, [], false, false)) - tp, false + tp, TypeDirectedConversionUsed.No, None else - AdjustRequiredTypeForTypeDirectedConversions infoReader false calledArgTy callerArgTy m + AdjustCalledArgTypeForTypeDirectedConversionsAndAutoQuote infoReader ad callerArgTy calledArgTy calledArg m // FSharpMethod(x = arg), optional F#-style argument, should have option type | CalleeSide -> @@ -259,10 +343,9 @@ let AdjustCalledArgTypeForOptionals (infoReader: InfoReader) enforceNullableOpti destOptionTy g calledArgTy else calledArgTy - AdjustRequiredTypeForTypeDirectedConversions infoReader false calledArgTy2 callerArgTy m + 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 @@ -279,15 +362,16 @@ let AdjustCalledArgTypeForOptionals (infoReader: InfoReader) enforceNullableOpti // 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, false + calledArgTy, TypeDirectedConversionUsed.No, None else // If the called method argument is an inref type, then the caller may provide a byref or value @@ -298,23 +382,18 @@ let AdjustCalledArgType (infoReader: InfoReader) isConstraint enforceNullableOpt else destByrefTy g calledArgTy #else - calledArgTy, false + 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, false + calledArgTy, TypeDirectedConversionUsed.No, None else - mkRefCellTy g (destByrefTy g calledArgTy), false + mkRefCellTy g (destByrefTy g calledArgTy), TypeDirectedConversionUsed.No, None else - // TODO: consider interaction with optional arguments - // We should swap the order of these calls, first stripping the optionality - // then making the type directed conversion - let calledArgTy2, usesTDC = AdjustCalledArgTypeForTypeDirectedConversionsAndLinqExpressionsAndAutoQuote infoReader callerArgTy calledArg m - let calledArgTy3, usesTDC2 = AdjustCalledArgTypeForOptionals infoReader enforceNullableOptionalsKnownTypes calledArg calledArgTy2 callerArg - calledArgTy3, usesTDC || usesTDC2 + AdjustCalledArgTypeForOptionals infoReader ad enforceNullableOptionalsKnownTypes calledArg calledArgTy callerArg //------------------------------------------------------------------------- // CalledMeth @@ -664,7 +743,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. @@ -672,7 +751,7 @@ let ExamineArgumentForLambdaPropagation (infoReader: InfoReader) (arg: AssignedC let countOfCallerLambdaArg = InferLambdaArgsForLambdaPropagation argExpr // Adjust for Expression<_>, Func<_, _>, ... - let adjustedCalledArgTy, _usesTDC = 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 @@ -690,9 +769,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) @@ -1047,25 +1126,36 @@ let CoerceFromFSharpFuncToDelegate g amap infoReader ad callerArgTy m callerArgE BuildNewDelegateExpr (None, g, amap, delegateTy, invokeMethInfo, delArgTys, callerArgExpr, callerArgTy, m) // Handle adhoc argument conversions -let AdjustExprForTypeDirectedConversions (g: TcGlobals) amap infoReader ad reqdTy actualTy m expr = +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.ImplicitConversion && typeEquiv g g.int64_ty reqdTy && typeEquiv g g.int32_ty actualTy then + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.int64_ty reqdTy && typeEquiv g g.int32_ty actualTy then mkCallToInt64Operator g m actualTy expr // Adhoc int32 --> float32 - elif g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion && typeEquiv g g.float32_ty reqdTy && typeEquiv g g.int32_ty actualTy then + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.float32_ty reqdTy && typeEquiv g g.int32_ty actualTy then mkCallToSingleOperator g m actualTy expr // Adhoc int32 --> float64 - elif g.langVersion.SupportsFeature LanguageFeature.ImplicitConversion && typeEquiv g g.float_ty reqdTy && typeEquiv g g.int32_ty actualTy then + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.int32_ty actualTy then mkCallToDoubleOperator g m actualTy expr - // TODO: consider op_Implicit - // TODO: consider Nullable - else - mkCoerceIfNeeded g reqdTy actualTy expr + else + match TryFindRelevantImplicitConversion infoReader ad reqdTy actualTy m with + | Some (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 (g: TcGlobals) amap infoReader ad isOutArg calledArgTy (reflArgInfo: ReflectedArgInfo) callerArgTy m callerArgExpr = +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) @@ -1075,11 +1165,6 @@ let AdjustCallerArgExpr (g: TcGlobals) amap infoReader ad isOutArg calledArgTy ( Some wrap, callerArgExprAddress #endif - 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 @@ -1094,7 +1179,7 @@ let AdjustCallerArgExpr (g: TcGlobals) amap infoReader ad isOutArg calledArgTy ( None, callerArgExpr else - let callerArgExpr2 = AdjustExprForTypeDirectedConversions g amap infoReader ad calledArgTy callerArgTy m 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. @@ -1214,7 +1299,7 @@ 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) ad (assignedArg: AssignedCalledArg<_>) = +let AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName (infoReader: InfoReader) ad (assignedArg: AssignedCalledArg<_>) = let g = infoReader.g let amap = infoReader.amap let callerArg = assignedArg.CallerArg @@ -1246,7 +1331,7 @@ let AdjustCallerArgForOptional tcFieldInit eCallerMemberName (infoReader: InfoRe if isOptCallerArg then errorR(Error(FSComp.SR.tcFormalArgumentIsNotOptional(), m)) if isNullableTy g calledArgTy then let calledNonOptTy = destNullableTy g calledArgTy - let _, callerArgExpr2 = AdjustCallerArgExpr g amap infoReader ad isOutArg calledNonOptTy reflArgInfo callerArgTy m callerArgExpr + 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 @@ -1274,11 +1359,11 @@ let AdjustCallerArgForOptional tcFieldInit eCallerMemberName (infoReader: InfoRe // 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)) let calledNonOptTy = destNullableTy g calledArgTy - let _, callerArgExpr2 = AdjustCallerArgExpr g amap infoReader ad isOutArg calledNonOptTy reflArgInfo callerArgTy m callerArgExpr + 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) - let _, callerArgExpr2 = AdjustCallerArgExpr g amap infoReader ad isOutArg calledArgTy reflArgInfo callerArgTy m callerArgExpr + let _, callerArgExpr2 = AdjustCallerArgExpr tcVal g amap infoReader ad isOutArg calledArgTy reflArgInfo callerArgTy m callerArgExpr callerArgExpr2 | CalleeSide -> @@ -1289,7 +1374,7 @@ let AdjustCallerArgForOptional tcFieldInit eCallerMemberName (infoReader: InfoRe // FSharpMethod(x=b) when FSharpMethod(A) --> FSharpMethod(?x=Some(b :> A)) if isOptionTy g calledArgTy then let calledNonOptTy = destOptionTy g calledArgTy - let _, callerArgExpr2 = AdjustCallerArgExpr g amap infoReader ad isOutArg calledNonOptTy reflArgInfo callerArgTy m callerArgExpr + let _, callerArgExpr2 = AdjustCallerArgExpr tcVal g amap infoReader ad isOutArg calledNonOptTy reflArgInfo callerArgTy m callerArgExpr mkSome g calledNonOptTy callerArgExpr2 m else assert false @@ -1317,7 +1402,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) ad (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) @@ -1334,8 +1419,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 ad) unnamedArgs - let adjustedAssignedNamedArgs = List.map (AdjustCallerArgForOptional tcFieldInit eCallerMemberName infoReader ad) 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 @@ -1352,7 +1437,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) @@ -1368,7 +1453,7 @@ let AdjustParamArrayCallerArgs g amap infoReader ad (calledMeth: CalledMeth<_>) paramArrayCallerArgs |> List.map (fun callerArg -> let (CallerArg(callerArgTy, m, isOutArg, callerArgExpr)) = callerArg - AdjustCallerArgExpr 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) @@ -1383,7 +1468,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 @@ -1402,10 +1487,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 ad calledMeth mItem mMethExpr + AdjustCallerArgsForOptionals tcVal tcFieldInit eCallerMemberName infoReader ad calledMeth mItem mMethExpr let outArgs, outArgExprs, outArgTmpBinds = AdjustOutCallerArgs g calledMeth mMethExpr @@ -1428,7 +1513,7 @@ let AdjustCallerArgs tcFieldInit eCallerMemberName (infoReader: InfoReader) ad ( let calledArgTy = assignedArg.CalledArg.CalledArgumentType let (CallerArg(callerArgTy, m, _, e)) = assignedArg.CallerArg - AdjustCallerArgExpr 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 diff --git a/src/fsharp/MethodCalls.fsi b/src/fsharp/MethodCalls.fsi index 34d459fbe93..12cba3b789b 100644 --- a/src/fsharp/MethodCalls.fsi +++ b/src/fsharp/MethodCalls.fsi @@ -7,6 +7,7 @@ open Internal.Utilities open FSharp.Compiler open FSharp.Compiler.AccessibilityLogic +open FSharp.Compiler.ErrorLogger open FSharp.Compiler.Import open FSharp.Compiler.InfoReader open FSharp.Compiler.Infos @@ -15,6 +16,7 @@ open FSharp.Compiler.SyntaxTree open FSharp.Compiler.Text open FSharp.Compiler.TcGlobals open FSharp.Compiler.TypedTree +open FSharp.Compiler.TypedTreeOps #if !NO_EXTENSIONTYPING open FSharp.Compiler.ExtensionTyping @@ -81,8 +83,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 @@ -92,16 +97,50 @@ 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 * bool +/// 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 -> isConstraint:bool -> reqdTy: TType -> actualTy:TType -> m: range -> TType * bool +val AdjustRequiredTypeForTypeDirectedConversions: + infoReader:InfoReader -> + ad: AccessorDomain -> + 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 @@ -251,7 +290,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 @@ -292,14 +331,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 AdjustExprForTypeDirectedConversions: g: TcGlobals -> amap:ImportMap -> infoReader:InfoReader -> ad:AccessorDomain -> reqdTy:TType -> actualTy:TType -> m:range -> expr:Expr -> Expr - -val AdjustCallerArgExpr: 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/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index aefc534fb84..67377e90834 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -77,6 +77,11 @@ Atribut sestavení {0} odkazuje na navržené sestavení {1}, které se nedá načíst nebo neexistuje. Ohlášená výjimka: {2} – {3} + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + applicative computation expressions aplikativní výpočetní výrazy @@ -107,11 +112,6 @@ řez od konce - - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions - - implicit yield implicitní yield @@ -322,6 +322,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. Výstup ze zadání {0} --version v adresáři {1} byl {2} a ukončovací kód byl {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'. + 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'. + + 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. @@ -357,6 +362,11 @@ Typy Byref nejsou v deklaraci otevřeného typu povolené. + + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' Neshoda v interpolovaném řetězci. Interpolované řetězce nemůžou používat specifikátory formátu %, pokud se každému z nich nezadá nějaký výraz, např. %d{{1+1}}. diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index 5f97c380a00..f45a526ad2c 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -77,6 +77,11 @@ Das Assemblyattribut "{0}" verweist auf eine Designerassembly "{1}", die entweder nicht geladen werden kann oder nicht vorhanden ist. Gemeldete Ausnahme: {2} – {3} + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + applicative computation expressions applikative Berechnungsausdrücke @@ -107,11 +112,6 @@ Segmentierung ab Ende - - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions - - implicit yield implizite yield-Anweisung @@ -322,6 +322,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. Ausgabe von "{0} --version" im Verzeichnis "{1}": {2}. Exitcode: {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'. + 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'. + + 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. @@ -357,6 +362,11 @@ Byref-Typen sind in einer Deklaration für offene Typen nicht zulässig. + + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' Konflikt in interpolierter Zeichenfolge. Interpolierte Zeichenfolgen dürfen keine Formatbezeichner vom Typ "%" verwenden, es sei denn, jeder erhält einen Ausdruck, z. B. "%d{{1+1}}" diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index e7bc48797fe..ce8c974fcae 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -77,6 +77,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}. + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + applicative computation expressions expresiones de cálculo aplicativas @@ -107,11 +112,6 @@ segmentación desde el final - - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions - - implicit yield elemento yield implícito @@ -322,6 +322,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'. + 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'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Esta versión de F# no admite esta característica. Es posible que tenga que agregar /langversion:preview para usarla. @@ -357,6 +362,11 @@ No se permiten tipos byref en una declaración de tipo abierto. + + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' La cadena interpolada no coincide. Las cadenas interpoladas no pueden usar los especificadores de formato "%", a menos que se les proporcione una expresión individualmente; por ejemplo, "%d{{1+1}}". diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index fc6e721dd75..5c970b96b73 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -77,6 +77,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} + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + applicative computation expressions expressions de calcul applicatives @@ -107,11 +112,6 @@ découpage depuis la fin - - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions - - implicit yield yield implicite @@ -322,6 +322,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'. + 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'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Cette fonctionnalité n'est pas prise en charge dans cette version de F#. Vous devrez peut-être ajouter /langversion:preview pour pouvoir utiliser cette fonctionnalité. @@ -357,6 +362,11 @@ Les types Byref ne sont pas autorisés dans une déclaration de type ouverte. + + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' Incompatibilité dans la chaîne interpolée. Les chaînes interpolées ne peuvent pas utiliser les spécificateurs de format '%' à moins de recevoir une expression, par exemple '%d{{1+1}}' diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index 1bb64339ba4..a7d0828306a 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -77,6 +77,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} + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + applicative computation expressions espressioni di calcolo applicativo @@ -107,11 +112,6 @@ sezionamento dalla fine - - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions - - implicit yield istruzione yield implicita @@ -322,6 +322,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'. + 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'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Questa funzionalità non è supportata in questa versione di F#. Per usare questa funzionalità, potrebbe essere necessario aggiungere /langversion:preview. @@ -357,6 +362,11 @@ I tipi byref non sono consentiti in una dichiarazione di tipo aperto. + + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' Mancata corrispondenza nella stringa interpolata. Nelle stringhe interpolate non è possibile usare gli identificatori di formato '%' a meno che non si indichi un'espressione per ognuno di essi, ad esempio '%d{{1+1}}' diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index a280cec07e9..77086795ca2 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -77,6 +77,11 @@ アセンブリ属性 '{0}' は、デザイナー アセンブリ '{1}' を参照していますが、これは読み込むことができないか、存在していません。報告された例外: {2} - {3} + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + applicative computation expressions 適用できる計算式 @@ -107,11 +112,6 @@ 開始と終了を指定したスライス - - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions - - implicit yield 暗黙的な yield @@ -322,6 +322,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'. + 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'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. この機能は、このバージョンの F# ではサポートされていません。この機能を使用するには、/langversion:preview の追加が必要な場合があります。 @@ -357,6 +362,11 @@ Byref 型は、オープン型宣言では使用できません。 + + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' 補間された文字列が一致しません。'%d{{1+1}}' などの式が指定されている場合を除き、補間された文字列では '%' 書式指定子を使用できません diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index 2d4186317b9..124cdcfc74a 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -77,6 +77,11 @@ '{0}' 어셈블리 특성이 로드할 수 없거나 존재하지 않는 디자이너 어셈블리'{1}'을(를) 참조합니다. 보고된 예외: {2} - {3} + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + applicative computation expressions 적용 가능한 계산 식 @@ -107,11 +112,6 @@ 끝에서부터 조각화 - - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions - - implicit yield 암시적 yield @@ -322,6 +322,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'. + 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'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. 이 기능은 이 F# 버전에서 지원되지 않습니다. 이 기능을 사용하기 위해 /langversion:preview를 추가해야 할 수도 있습니다. @@ -357,6 +362,11 @@ Byref 형식은 개방형 형식 선언에서 허용되지 않습니다. + + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' 보간 문자열의 불일치. 각 보간 문자열에 식(예: '%d{{1+1}}')이 지정되지 않는 한 '%' 형식 지정자를 사용할 수 없습니다. diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index 13bb0af4bb7..edc3ec8f254 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -77,6 +77,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} + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + applicative computation expressions praktyczne wyrażenia obliczeniowe @@ -107,11 +112,6 @@ wycinanie od końca - - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions - - implicit yield niejawne słowo kluczowe yield @@ -322,6 +322,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'. + 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'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Ta funkcja nie jest obsługiwana w tej wersji języka F#. Aby korzystać z tej funkcji, może być konieczne dodanie parametru /langversion:preview. @@ -357,6 +362,11 @@ Typy ByRef są niedozwolone w deklaracji typu otwartego. + + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' Niezgodność w interpolowanym ciągu. W interpolowanych ciągach nie można używać specyfikatorów formatu „%”, chyba że każdemu z nich odpowiada wyrażenie, na przykład „%d{{1+1}}”. diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index 958dab0dc8c..bf9473b1866 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -77,6 +77,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} + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + applicative computation expressions expressões de computação aplicáveis @@ -107,11 +112,6 @@ divisão começando no final - - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions - - implicit yield yield implícito @@ -322,6 +322,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'. + 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'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Este recurso não tem suporte nesta versão do F#. Talvez seja necessário adicionar /langversion:preview para usar este recurso. @@ -357,6 +362,11 @@ Os tipos Byref não são permitidos em uma declaração de tipo aberto. + + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' Incompatibilidade na cadeia de caracteres interpolada. As cadeias de caracteres interpoladas não podem usar especificadores de formato '%', a menos que cada um receba uma expressão, por exemplo, '%d{{1+1}}' diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index ba2871ca7da..af18a3d8678 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -77,6 +77,11 @@ Атрибут сборки "{0}" ссылается на сборку конструктора "{1}", которая не может быть загружена или не существует. Получено исключение: {2} — {3} + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + applicative computation expressions применимые вычислительные выражения @@ -107,11 +112,6 @@ срезы от конца - - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions - - implicit yield неявное использование yield @@ -322,6 +322,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'. + 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'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Эта функция не поддерживается в данной версии F#. Возможно, потребуется добавить/langversion:preview, чтобы использовать эту функцию. @@ -357,6 +362,11 @@ Типы ByRef запрещены в объявлении открытого типа. + + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' Несоответствие в интерполированной строке. В интерполированных строках запрещено использовать описатели формата "%", если только каждому из них не назначено выражение, например "'%d{{1+1}}". diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index eec54a3f233..ada7a4d1f90 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -77,6 +77,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} + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + applicative computation expressions uygulama hesaplama ifadeleri @@ -107,11 +112,6 @@ uçtan dilimleme - - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions - - implicit yield örtük yield @@ -322,6 +322,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'. + 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'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. Bu özellik, bu F# sürümünde desteklenmiyor. Bu özelliği kullanabilmeniz için /langversion:preview eklemeniz gerekebilir. @@ -357,6 +362,11 @@ Açık tür bildiriminde Byref türlerine izin verilmez. + + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' Düz metin arasına kod eklenmiş dizede uyuşmazlık. Düz metin arasına kod eklenmiş dizeler, her birine '%d{{1+1}}' gibi bir ifade verilmedikçe '%' biçim belirticilerini kullanamaz diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index 23d95c576c3..659c3ab80d7 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -77,6 +77,11 @@ 程序集属性“{0}”引用了无法加载或不存在的设计器程序集“{1}”。报告的异常是: {2} - {3} + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + applicative computation expressions 适用的计算表达式 @@ -107,11 +112,6 @@ 从端切片 - - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions - - implicit yield 隐式 yield @@ -322,6 +322,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'. + 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'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. 此版本的 F# 不支持此功能。你可能需要添加 /langversion:preview 才可使用此功能。 @@ -357,6 +362,11 @@ 在开放类型声明中不允许使用 Byref 类型。 + + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' 在内插字符串中不匹配。内插字符串不会使用 "%" 格式说明符,除非为每个字符串提供像 "'%d{{1+1}}" 这样的表达式 diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index 6e31af6d1f8..4e12d9f3a90 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -77,6 +77,11 @@ 無法載入組件屬性 '{0}' 參考的設計工具組件 '{1}' 或其不存在。回報的例外狀況: {2} - {3} + + implicit upcasts and other conversions for function returns, bindings and other expressions + implicit upcasts and other conversions for function returns, bindings and other expressions + + applicative computation expressions 適用的計算運算式 @@ -107,11 +112,6 @@ 從尾端切割 - - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions - - implicit yield 隱含 yield @@ -322,6 +322,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'. + 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'. + + This feature is not supported in this version of F#. You may need to add /langversion:preview to use this feature. 此版本的 F# 不支援此功能。您可能需要新增 /langversion:preview 才能使用此功能。 @@ -357,6 +362,11 @@ 開放式類型宣告中不允許 Byref 類型。 + + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' 插補字串不相符。除非每個插補字串都有一個運算式,否則不可使用 '%' 格式指定名稱,例如 '%d{{1+1}}' 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..6455fed873d --- /dev/null +++ b/tests/fsharp/core/auto-widen/5.0/test.bsl @@ -0,0 +1,591 @@ + +test.fsx(8,20,8,21): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(11,20,11,41): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(14,20,14,44): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(17,21,17,24): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + ''a * 'b' + +test.fsx(25,31,25,32): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(30,27,30,28): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(30,29,30,30): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(33,56,33,57): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(33,58,33,59): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(36,43,36,44): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(36,45,36,46): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(41,41,41,42): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(42,48,42,49): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(42,50,42,51): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(45,30,45,31): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(45,32,45,33): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(51,22,51,24): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(52,22,52,23): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(53,28,53,29): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(53,30,53,31): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'int64'. This element has type 'int'. + +test.fsx(53,32,53,33): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'int64'. This element has type 'int'. + +test.fsx(53,34,53,35): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'int64'. This element has type 'int'. + +test.fsx(54,28,54,29): typecheck error FS0001: This expression was expected to have type + 'float' +but here has type + 'int' + +test.fsx(54,30,54,31): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'float'. This element has type 'int'. + +test.fsx(54,32,54,33): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'float'. This element has type 'int'. + +test.fsx(54,34,54,35): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'float'. This element has type 'int'. + +test.fsx(55,30,55,31): typecheck error FS0001: This expression was expected to have type + 'float32' +but here has type + 'int' + +test.fsx(55,32,55,33): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'float32'. This element has type 'int'. + +test.fsx(55,34,55,35): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'float32'. This element has type 'int'. + +test.fsx(55,36,55,37): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'float32'. This element has type 'int'. + +test.fsx(56,22,56,43): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(57,28,57,49): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(57,50,57,71): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'int64'. This element has type 'int'. + +test.fsx(60,20,60,23): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(60,20,60,23): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(61,22,61,25): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(61,22,61,25): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(62,26,62,29): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(62,26,62,29): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(86,13,86,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(92,13,92,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(109,20,109,21): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(114,14,114,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(115,19,115,20): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(115,22,115,23): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(120,14,120,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(121,19,121,20): typecheck error FS0001: This expression was expected to have type + 'double' +but here has type + 'int' + +test.fsx(121,22,121,23): typecheck error FS0001: This expression was expected to have type + 'double' +but here has type + 'int' + +test.fsx(128,18,128,19): typecheck error FS0001: This expression was expected to have type + 'C' +but here has type + 'int' + +test.fsx(133,18,133,19): typecheck error FS0001: This expression was expected to have type + 'int64' +but here has type + 'int' + +test.fsx(138,18,138,19): typecheck error FS0001: This expression was expected to have type + 'decimal' +but here has type + 'int' + +test.fsx(140,18,140,19): typecheck error FS0001: This expression was expected to have type + 'decimal' +but here has type + 'int' + +test.fsx(142,39,142,41): typecheck error FS0001: This expression was expected to have type + 'Xml.Linq.XNamespace' +but here has type + 'string' + +test.fsx(147,18,147,20): typecheck error FS0001: This expression was expected to have type + 'Xml.Linq.XNamespace' +but here has type + 'string' + +test.fsx(152,18,152,21): typecheck error FS0001: This expression was expected to have type + 'Xml.Linq.XName' +but here has type + 'string' + +test.fsx(158,18,158,19): typecheck error FS0001: The type 'int' is not compatible with the type 'C' + +test.fsx(158,17,158,20): typecheck error FS0193: Type constraint mismatch. The type + 'int' +is not compatible with type + 'C' + + +test.fsx(165,18,165,21): typecheck error FS0001: The type 'Y' is not compatible with the type 'X' + +test.fsx(165,17,165,22): typecheck error FS0193: Type constraint mismatch. The type + 'Y' +is not compatible with type + 'X' + + +test.fsx(171,20,171,21): typecheck error FS0001: This expression was expected to have type + 'C' +but here has type + 'int' + +test.fsx(173,15,173,16): typecheck error FS0001: The type 'int' is not compatible with the type 'C' + +test.fsx(179,27,179,28): typecheck error FS0001: This expression was expected to have type + 'Nullable' +but here has type + 'int' + +test.fsx(181,15,181,16): typecheck error FS0001: This expression was expected to have type + 'Nullable' +but here has type + 'int' + +test.fsx(184,20,184,23): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + ''a * 'b' + +test.fsx(185,26,185,27): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(185,28,185,29): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(188,55,188,56): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(188,57,188,58): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(191,48,191,49): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(191,50,191,53): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'float' + +test.fsx(194,32,194,33): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(194,34,194,37): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'float' + +test.fsx(197,42,197,43): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(197,44,197,45): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(203,13,203,14): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(203,16,203,19): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'byte' + +test.fsx(203,30,203,33): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'float' + +test.fsx(203,35,203,36): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(209,40,209,41): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(212,43,212,44): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(212,52,212,55): typecheck error FS0001: All branches of a pattern match expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. + +test.fsx(212,63,212,66): typecheck error FS0001: All branches of a pattern match expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'byte'. + +test.fsx(214,47,214,48): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(214,49,214,50): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(219,34,219,35): typecheck error FS0001: This expression was expected to have type + 'IComparable' +but here has type + 'int' + +test.fsx(222,28,222,37): typecheck error FS0001: This expression was expected to have type + 'Array' +but here has type + 'uint16 []' + +test.fsx(224,28,224,36): typecheck error FS0001: This expression was expected to have type + 'Array' +but here has type + ''a []' + +test.fsx(226,34,226,36): typecheck error FS0001: This expression was expected to have type + 'IComparable' +but here has type + 'Numerics.BigInteger' + +test.fsx(229,42,229,61): typecheck error FS0001: This expression was expected to have type + 'IComparable' +but here has type + 'string' + +test.fsx(232,42,232,66): typecheck error FS0001: This expression was expected to have type + 'IComparable' +but here has type + 'string' + +test.fsx(234,19,234,43): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(236,34,236,58): typecheck error FS0001: This expression was expected to have type + 'IComparable' +but here has type + 'string' + +test.fsx(241,33,241,34): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(241,35,241,36): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(242,33,242,38): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(242,39,242,40): 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(244,42,244,43): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(244,53,244,56): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'float' + +test.fsx(245,66,245,69): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'float' + +test.fsx(246,80,246,83): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'float' + +test.fsx(248,19,248,20): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(249,20,249,27): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(250,19,250,21): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(251,20,251,31): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(252,20,252,43): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'IComparable' + +test.fsx(253,20,253,22): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(254,20,254,22): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(255,19,255,74): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'ICloneable' + +test.fsx(256,19,256,21): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(257,19,257,28): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(257,19,257,28): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(258,22,258,24): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(261,32,261,33): typecheck error FS0001: The 'if' expression needs to have type 'obj' to satisfy context type requirements. It currently has type 'int'. + +test.fsx(261,39,261,42): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. + +test.fsx(262,33,262,34): typecheck error FS0001: The 'if' expression needs to have type 'obj' to satisfy context type requirements. It currently has type 'int'. + +test.fsx(262,40,262,43): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. + +test.fsx(263,33,263,34): typecheck error FS0001: The 'if' expression needs to have type 'obj' to satisfy context type requirements. It currently has type 'int'. + +test.fsx(263,50,263,53): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'byte'. + +test.fsx(263,59,263,62): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. + +test.fsx(266,23,266,24): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(266,35,266,38): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'float' + +test.fsx(269,23,269,24): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(272,43,272,44): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(272,52,272,55): typecheck error FS0001: All branches of a pattern match expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. + +test.fsx(275,19,275,20): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'int' + +test.fsx(276,32,276,33): typecheck error FS0001: The 'if' expression needs to have type 'obj' to satisfy context type requirements. It currently has type 'int'. + +test.fsx(276,39,276,42): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. + +test.fsx(280,9,280,11): typecheck error FS0001: This expression was expected to have type + 'obj' +but here has type + 'string' + +test.fsx(281,7,281,22): typecheck error FS0001: This expression was expected to have type + 'unit' +but here has type + 'obj' + +test.fsx(283,32,283,35): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'int'. This branch returns a value of type 'float'. diff --git a/tests/fsharp/core/auto-widen/auto-widen.fsx b/tests/fsharp/core/auto-widen/5.0/test.fsx similarity index 76% rename from tests/fsharp/core/auto-widen/auto-widen.fsx rename to tests/fsharp/core/auto-widen/5.0/test.fsx index 9f7493d3069..7717c5b7393 100644 --- a/tests/fsharp/core/auto-widen/auto-widen.fsx +++ b/tests/fsharp/core/auto-widen/5.0/test.fsx @@ -1,3 +1,6 @@ +#r "System.Xml.Linq.dll" +#r "System.Xml.XDocument.dll" + open System module BasicTypeDirectedConversionsToObj = @@ -73,31 +76,31 @@ module Overloads1 = module Overloads2 = type C() = static member M1(x:int) = failwith "nope" - static member M1(x:int64) = 1 + 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) = 1 + 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) = 1 + 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) = 1 + 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) = 1 + static member M1(?x:int64) = printfn "ok at line %s" __LINE__ let x = C.M1(x=2L) module Optionals1 = @@ -117,6 +120,66 @@ module ParamArray2 = 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 rec ConvertViaOpImplicit5 = + type Y() = + static member op_Implicit(y:Y) = X() + type X() = + static member M1(x:X) = 1 + 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 _ : obj = (1,2) let _ : obj * obj = (1,2) @@ -220,4 +283,4 @@ let annotations = let f3 x = if true then 1 else 3.0 #endif -printfn "test done" \ No newline at end of file +printfn "test done" 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..b910ad7fa75 --- /dev/null +++ b/tests/fsharp/core/auto-widen/preview/test.bsl @@ -0,0 +1,4 @@ + +test.fsx(169,18,169,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'Y' to type 'X'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(169,18,169,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'Y' to type 'X'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. 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..8ab7e276ebe --- /dev/null +++ b/tests/fsharp/core/auto-widen/preview/test.fsx @@ -0,0 +1,303 @@ +(* +#r "System.Xml.Linq.dll" +#r "System.Xml.XDocument.dll" + +let failures = ref [] + +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) } + +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 _ : obj = (1,2) + let _ : obj * obj = (1,2) + + // structure through let + let _ : (obj * obj) = (let x = 1 in let y = 2 in (x,y)) + + // structure through let rec + let _ : (obj * obj) = (let rec f x = x in (3,4.0)) + + // structure through sequence + let _ : (obj * obj) = (); (3,4.0) + + // struct tuple + let _ : struct (obj * obj) = struct (1,2) + + // record (both field and overall result) + // let _ : obj = { F1 = (1, 2) } // TODO + + // record (both field and overall result) + { F1 = (1, 2uy) }.F1 <- (3.0, 4) + + // anon record + let _ : {| A: obj |} = {| A = 1 |} + + // lambda return + let _ : (unit -> obj) = (fun () -> 1) + + // function lambda return + let _ : (int -> obj) = (function 1 -> 1 | 2 -> 3.0 | _ -> 4uy) + + let _ : (unit -> obj * obj) = (fun () -> (1,2)) + + // constants + (1 :> System.IComparable) |> ignore + + let _ : System.IComparable = 1 + + // array constants + let _ : System.Array = [| 1us |] + + let _ : System.Array = [| 1I |] + + let _ : System.IComparable = 1I + + // property + let _ : System.IComparable = System.String.Empty + + // method + let _ : System.IComparable = System.String.Format("") + + let _ : obj = System.String.Format("") + + let _ : System.IComparable = System.String.Format("") + + // array constants + + let _ : obj[] = [| 1 |] + let _ : (obj * obj)[] = [| (1,1) |] + let _ : (obj * obj)[] = [| ("abc",1) |] + let _ : (string * obj)[] = [| ("abc",1) |] + let _ : (string * obj)[] = [| ("abc",1); ("abc",3.0) |] + let _ : (string * obj)[] = [| Unchecked.defaultof<_>; ("abc",3.0) |] + let _ : struct (string * obj)[] = [| Unchecked.defaultof<_>; struct ("abc",3.0) |] + + let _ : obj = 1 + let _ : obj = (1 : int) + let _ : obj = "" + let _ : obj = ("" : string) + let _ : obj = ("" : System.IComparable) + let _ : obj = ("" : _) + let _ : obj = ("" : obj) + let _ : obj = { new System.ICloneable with member x.Clone() = obj() } + let _ : obj = "" + let _ : obj = string "" + let _ : obj = id "" + + // conditional + let _ : obj = if true then 1 else 3.0 + let _ : obj = (if true then 1 else 3.0) + let _ : obj = (if true then 1 elif true then 2uy else 3.0) + + // try-with + let _ : obj = try 1 with _ -> 3.0 + + // try-finally + let _ : obj = try 1 finally () + + // match + let _ : obj = match true with true -> 1 | _ -> 3.0 + () + +let f1 () : obj = 1 +let f2 () : obj = if true then 1 else 3.0 + +#if NEGATIVE +let annotations = + (id "" : obj) |> ignore /// note, the 'obj' annotation correctly instantiates the type variable to 'obj' + ((if true then ()) : obj) |> ignore + +let f3 x = if true then 1 else 3.0 +#endif + +printfn "test done" + +let aa = + match !failures with + | [] -> + stdout.WriteLine "Test Passed" + System.IO.File.WriteAllText("test.ok","ok") + exit 0 + | _ -> + stdout.WriteLine "Test Failed" + exit 1 + +*) diff --git a/tests/fsharp/tests.fs b/tests/fsharp/tests.fs index fbe6c29f6cc..61b1c151b09 100644 --- a/tests/fsharp/tests.fs +++ b/tests/fsharp/tests.fs @@ -54,6 +54,21 @@ 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-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:3386 --warnaserror+" } + singleVersionedNegTest cfg "preview" "test" + [] let ``comprehensions-FSC_BASIC`` () = singleTestBuildAndRun' "core/comprehensions" FSC_BASIC @@ -61,10 +76,10 @@ module CoreTests = let ``comprehensions-FSI_BASIC`` () = singleTestBuildAndRun' "core/comprehensions" FSI_BASIC [] - let ``comprehensionshw-FSC_BASIC`` () = singleTestBuildAndRun' "core/comprehensions-hw" FSC_BASIC + let ``comprehensions-hw-FSC_BASIC`` () = singleTestBuildAndRun' "core/comprehensions-hw" FSC_BASIC [] - let ``comprehensionshw-FSI_BASIC`` () = singleTestBuildAndRun' "core/comprehensions-hw" FSI_BASIC + let ``comprehensions-hw-FSI_BASIC`` () = singleTestBuildAndRun' "core/comprehensions-hw" FSI_BASIC [] let ``genericmeasures-FSC_BASIC`` () = singleTestBuildAndRun' "core/genericmeasures" FSC_BASIC @@ -870,35 +885,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" [] @@ -2465,14 +2480,7 @@ module TypecheckTests = let ``type check neg19`` () = singleNegTest (testConfig' "typecheck/sigs") "neg19" [] - let ``type check neg20 version 5_0`` () = - let cfg = testConfig' "typecheck/sigs/version50" - singleVersionedNegTest cfg "5.0" "neg20" - - [] - let ``type check neg20 version preview`` () = - let cfg = testConfig' "typecheck/sigs" - singleVersionedNegTest cfg "preview" "neg20" + let ``type check neg20`` () = singleNegTest (testConfig' "typecheck/sigs") "neg20" [] let ``type check neg21`` () = singleNegTest (testConfig' "typecheck/sigs") "neg21" @@ -2495,13 +2503,6 @@ 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" [] From d20062bd460f8cf58512cb30e393caa3f0a20b02 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 26 Jan 2021 16:56:35 +0000 Subject: [PATCH 20/42] update baselines --- src/fsharp/CheckExpressions.fs | 24 ++-- src/fsharp/CheckExpressions.fsi | 2 +- tests/fsharp/core/auto-widen/preview/test.bsl | 107 +++++++++++++++++- tests/fsharp/core/auto-widen/preview/test.fsx | 11 +- 4 files changed, 123 insertions(+), 21 deletions(-) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 7d67e913470..5bb925121aa 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -5289,22 +5289,22 @@ and TcExprOfUnknownType cenv env tpenv expr = let expr', tpenv = TcExpr cenv (MustEqual exprty) env tpenv expr expr', exprty, tpenv -and TcExprFlex cenv flex compat (desiredTy: TType) (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 desiredTy argty - let e', tpenv = TcExprFlex2 cenv argty env tpenv e - let e' = mkCoerceIfNeeded cenv.g desiredTy argty e' - e', tpenv + AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css synExpr.Range NoTrace desiredTy argty + let expr2, tpenv = TcExprFlex2 cenv argty env tpenv synExpr + let expr3 = mkCoerceIfNeeded cenv.g desiredTy argty expr2 + expr3, tpenv else - TcExprFlex2 cenv desiredTy env tpenv e + TcExprFlex2 cenv desiredTy env tpenv synExpr -and TcExprFlex2 cenv desiredTy env tpenv e = - TcExpr cenv (MustConvertTo desiredTy) env tpenv e +and TcExprFlex2 cenv desiredTy env tpenv synExpr = + TcExpr cenv (MustConvertTo desiredTy) env tpenv synExpr and TcExpr cenv ty (env: TcEnv) tpenv (expr: SynExpr) = // Start an error recovery handler @@ -9009,9 +9009,11 @@ and TcMethodApplication let expr = mkLetsBind mMethExpr outArgTmpBinds expr expr, tyOfExpr cenv.g expr - // Subsumption to return type - let callExpr2b = mkCoerceIfNeeded cenv.g returnTy.Commit exprty callExpr2 - + // Subsumption or conversion to return type + let callExpr2b = + let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g + AdjustExprForTypeDirectedConversions tcVal cenv.g cenv.amap cenv.infoReader env.AccessRights returnTy.Commit exprty mMethExpr callExpr2 + // Handle post-hoc property assignments let setterExprPrebinders, callExpr3 = let expr = callExpr2b diff --git a/src/fsharp/CheckExpressions.fsi b/src/fsharp/CheckExpressions.fsi index 5ae5a9cd8ec..8ec958e9517 100644 --- a/src/fsharp/CheckExpressions.fsi +++ b/src/fsharp/CheckExpressions.fsi @@ -659,7 +659,7 @@ val TcExprOfUnknownType: cenv:TcFileState -> env:TcEnv -> tpenv: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 -> desiredTy: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 /// Check a syntactic statement and convert it to a typed tree expression. val TcStmtThatCantBeCtorBody: cenv:TcFileState -> env:TcEnv -> tpenv:UnscopedTyparEnv -> expr:SynExpr -> Expr * UnscopedTyparEnv diff --git a/tests/fsharp/core/auto-widen/preview/test.bsl b/tests/fsharp/core/auto-widen/preview/test.bsl index b910ad7fa75..c4f1df62ddd 100644 --- a/tests/fsharp/core/auto-widen/preview/test.bsl +++ b/tests/fsharp/core/auto-widen/preview/test.bsl @@ -1,4 +1,107 @@ -test.fsx(169,18,169,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'Y' to type 'X'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(54,22,54,24): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(55,22,55,23): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(56,28,56,29): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(56,30,56,31): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(56,32,56,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(56,34,56,35): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(57,28,57,29): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(57,30,57,31): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(57,32,57,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(57,34,57,35): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(58,30,58,31): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float32'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(58,32,58,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float32'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(58,34,58,35): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float32'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(58,36,58,37): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float32'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(59,22,59,43): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(60,28,60,49): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(60,50,60,71): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(64,22,64,25): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(64,22,64,25): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(65,26,65,29): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(65,26,65,29): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(89,18,89,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(89,18,89,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(95,20,95,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(95,20,95,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(112,20,112,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(117,19,117,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(117,19,117,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(118,19,118,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(118,22,118,23): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(123,19,123,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'double'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(123,19,123,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'double'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(124,19,124,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'double'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(124,22,124,23): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'double'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(131,18,131,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(136,18,136,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(141,18,141,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'decimal'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(143,18,143,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'decimal'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(145,39,145,41): typecheck error FS3386: This expression uses an implicit conversion to convert type 'string' to type 'Xml.Linq.XNamespace'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(150,18,150,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'string' to type 'Xml.Linq.XNamespace'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(155,18,155,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'string' to type 'Xml.Linq.XName'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(161,18,161,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(168,18,168,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'Y' to type 'X'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(168,18,168,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'Y' to type 'X'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(174,20,174,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(176,15,176,16): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(182,27,182,28): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'Nullable'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(184,15,184,16): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'Nullable'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(284,7,284,22): typecheck error FS0001: This expression was expected to have type + 'unit' +but here has type + 'obj' + +test.fsx(286,32,286,35): typecheck error FS0193: Type constraint mismatch. The type + 'float' +is not compatible with type + 'int' -test.fsx(169,18,169,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'Y' to type 'X'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. diff --git a/tests/fsharp/core/auto-widen/preview/test.fsx b/tests/fsharp/core/auto-widen/preview/test.fsx index 8ab7e276ebe..ceb2a980cb1 100644 --- a/tests/fsharp/core/auto-widen/preview/test.fsx +++ b/tests/fsharp/core/auto-widen/preview/test.fsx @@ -1,8 +1,8 @@ -(* + #r "System.Xml.Linq.dll" #r "System.Xml.XDocument.dll" -let failures = ref [] +let mutable failures : string list = [] open System @@ -160,7 +160,6 @@ module ConvertViaOpImplicit4 = static member M1(C:C) = 1 let x = C.M1(2) -*) module ConvertViaOpImplicit5 = type X() = static member M1(x:X) = 1 @@ -168,7 +167,6 @@ module ConvertViaOpImplicit5 = 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>() @@ -291,13 +289,12 @@ let f3 x = if true then 1 else 3.0 printfn "test done" let aa = - match !failures with + match failures with | [] -> stdout.WriteLine "Test Passed" System.IO.File.WriteAllText("test.ok","ok") exit 0 | _ -> - stdout.WriteLine "Test Failed" + printfn "Test Failed, failures = %A" failures exit 1 -*) From efb4e7ef568841c2395002aeebc4440e6fd243e8 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 26 Jan 2021 19:18:44 +0000 Subject: [PATCH 21/42] fix bug in nullable codegen --- src/fsharp/MethodCalls.fs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/fsharp/MethodCalls.fs b/src/fsharp/MethodCalls.fs index 6ed5ebd4776..5ae4c1078e6 100644 --- a/src/fsharp/MethodCalls.fs +++ b/src/fsharp/MethodCalls.fs @@ -252,6 +252,10 @@ let rec AdjustRequiredTypeForTypeDirectedConversions (infoReader: InfoReader) ad elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.int32_ty actualTy then g.int32_ty, TypeDirectedConversionUsed.Yes(warn), None + // Adhoc float32--> float64 + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.float32_ty actualTy then + g.float32_ty, TypeDirectedConversionUsed.Yes(warn), None + // Adhoc based on op_Implicit, perhaps returing a new equational type constraint to // eliminate articifical constrained type variables. elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions then @@ -1138,12 +1142,19 @@ let rec AdjustExprForTypeDirectedConversions tcVal (g: TcGlobals) amap infoReade // Adhoc int32 --> int64 elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.int64_ty reqdTy && typeEquiv g g.int32_ty actualTy then mkCallToInt64Operator g m actualTy expr + // Adhoc int32 --> float32 elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.float32_ty reqdTy && typeEquiv g g.int32_ty actualTy then mkCallToSingleOperator g m actualTy expr + // Adhoc int32 --> float64 elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.int32_ty actualTy then mkCallToDoubleOperator g m actualTy expr + + // Adhoc float32 --> float64 + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.float32_ty actualTy then + mkCallToDoubleOperator g m actualTy expr + else match TryFindRelevantImplicitConversion infoReader ad reqdTy actualTy m with | Some (minfo, _) -> @@ -1330,9 +1341,12 @@ let AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName (infoReader: // T --> Nullable widening at callsites if isOptCallerArg then errorR(Error(FSComp.SR.tcFormalArgumentIsNotOptional(), m)) if isNullableTy g calledArgTy then - 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 + 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 From 953561532d4822e3d4eb0f8d973c15834769cb6b Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 27 Jan 2021 14:35:35 +0000 Subject: [PATCH 22/42] fix tests --- src/fsharp/MethodCalls.fs | 15 ++++--- tests/fsharp/tests.fs | 7 +++ tests/fsharp/typecheck/sigs/neg20.bsl | 63 ++++++++++++++++++++++++--- tests/fsharp/typecheck/sigs/neg24.bsl | 18 ++++++-- 4 files changed, 89 insertions(+), 14 deletions(-) diff --git a/src/fsharp/MethodCalls.fs b/src/fsharp/MethodCalls.fs index 5ae4c1078e6..daed6482c96 100644 --- a/src/fsharp/MethodCalls.fs +++ b/src/fsharp/MethodCalls.fs @@ -1369,12 +1369,15 @@ let AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName (infoReader: 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)) - 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 + 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) let _, callerArgExpr2 = AdjustCallerArgExpr tcVal g amap infoReader ad isOutArg calledArgTy reflArgInfo callerArgTy m callerArgExpr diff --git a/tests/fsharp/tests.fs b/tests/fsharp/tests.fs index 61b1c151b09..d09fad92c9b 100644 --- a/tests/fsharp/tests.fs +++ b/tests/fsharp/tests.fs @@ -2503,6 +2503,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 a6a3aadc4b7..4227ab07193 100644 --- a/tests/fsharp/typecheck/sigs/neg20.bsl +++ b/tests/fsharp/typecheck/sigs/neg20.bsl @@ -19,6 +19,11 @@ neg20.fs(32,32,32,35): typecheck error FS0001: This expression was expected to h 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 @@ -44,16 +49,37 @@ neg20.fs(45,19,45,22): typecheck error FS0001: This expression was expected to h 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(60,26,60,33): typecheck error FS0001: The type 'A' is not compatible with the type 'B' +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 of the same type as 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(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(61,27,61,35): typecheck error FS0001: The type 'B2' is not compatible with the type 'B1' +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(62,26,62,33): typecheck error FS0001: The type 'B' is not compatible with the type 'C' +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(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(71,34,71,42): typecheck error FS0001: Type mismatch. Expecting a 'A list' @@ -61,6 +87,11 @@ 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 @@ -79,9 +110,26 @@ but given a 'B list' The type 'A' does not match the type 'B' -neg20.fs(96,26,96,33): typecheck error FS0001: The type 'A' is not compatible with 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(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(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: The type 'A' is not compatible with the 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(108,12,108,16): typecheck error FS0001: Type mismatch. Expecting a 'B * B -> 'a' @@ -106,6 +154,11 @@ neg20.fs(128,19,128,22): typecheck error FS0001: This expression was expected to 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 diff --git a/tests/fsharp/typecheck/sigs/neg24.bsl b/tests/fsharp/typecheck/sigs/neg24.bsl index ffc702de46b..fcf7a40e45b 100644 --- a/tests/fsharp/typecheck/sigs/neg24.bsl +++ b/tests/fsharp/typecheck/sigs/neg24.bsl @@ -17,9 +17,17 @@ 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 FS0193: Type constraint mismatch. The type + 'int' +is not compatible with type + 'unit' + + +neg24.fs(302,36,302,37): typecheck error FS0193: Type constraint mismatch. The type + 'int' +is not compatible with type + 'unit' -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(304,11,305,32): typecheck error FS0193: Type constraint mismatch. The type 'int' @@ -29,7 +37,11 @@ is not compatible with type 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(309,31,309,32): typecheck error FS0193: Type constraint mismatch. The type + 'int' +is not compatible with type + 'unit' + 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'. From 22665d01964aa61e067b7d5a699f14bb4e0b97f3 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 27 Jan 2021 15:03:02 +0000 Subject: [PATCH 23/42] fix unions and records --- src/fsharp/CheckExpressions.fs | 18 ++- tests/fsharp/core/auto-widen/preview/test.bsl | 100 +++++++-------- tests/fsharp/core/auto-widen/preview/test.fsx | 121 +++++++++++------- 3 files changed, 134 insertions(+), 105 deletions(-) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 5bb925121aa..de8d5182f48 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -5718,13 +5718,12 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = | SynExpr.Record (inherits, optOrigExpr, flds, mWholeExpr) -> - // NOTE: TcExprLeafProtect is not used here because record expressions are used for class initialization where placing the subtype constraint is not enough - // TODO: allow subsumption for normal record expressions - - //TcExprLeafProtect cenv overallTy env mWholeExpr (fun overallTy -> - CallExprHasTypeSink cenv.tcSink (mWholeExpr, env.NameEnv, overallTy.Commit, 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 + TcExprLeafProtectExcept (fun ty -> requiresCtor || haveCtor || isRecdTy cenv.g ty) cenv overallTy env true mWholeExpr (fun overallTy -> TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr) - //) + ) | SynExpr.While (spWhile, synGuardExpr, synBodyExpr, m) -> UnifyTypes cenv env m overallTy.Commit cenv.g.unit_ty @@ -6982,9 +6981,7 @@ and TcAssertExpr cenv overallTy env (m: range) tpenv x = TcExpr cenv overallTy env tpenv callDiagnosticsExpr -and TcRecdExpr cenv (overallTy: OverallTy) env tpenv (inherits, optOrigExpr, flds, mWholeExpr) = - - let overallTy = overallTy.Commit // Type directed resolution of record expressions means must subsume explicitly with upcast or box or :> +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 @@ -7732,6 +7729,7 @@ and TcItemThen cenv (overallTy: OverallTy) env tpenv (tinstEnclosing, item, mIte | _ -> 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) @@ -7748,7 +7746,7 @@ and TcItemThen cenv (overallTy: OverallTy) env tpenv (tinstEnclosing, item, mIte | ((DelayedApp (atomicFlag, (FittedArgs args as origArg), mExprAndArg)) :: otherDelayed) -> // assert the overall result type if possible if isNil otherDelayed then - UnifyTypes cenv env mExprAndArg overallTy.Commit ucaseAppTy + UnifyOverallType cenv env mExprAndArg overallTy ucaseAppTy let numArgs = List.length args UnionCaseOrExnCheck env numArgTys numArgs mExprAndArg diff --git a/tests/fsharp/core/auto-widen/preview/test.bsl b/tests/fsharp/core/auto-widen/preview/test.bsl index c4f1df62ddd..b17a54f2b9d 100644 --- a/tests/fsharp/core/auto-widen/preview/test.bsl +++ b/tests/fsharp/core/auto-widen/preview/test.bsl @@ -1,106 +1,106 @@ -test.fsx(54,22,54,24): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(58,22,58,24): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(55,22,55,23): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(59,22,59,23): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(56,28,56,29): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(60,28,60,29): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(56,30,56,31): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(60,30,60,31): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(56,32,56,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(60,32,60,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(56,34,56,35): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(60,34,60,35): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(57,28,57,29): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(61,28,61,29): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(57,30,57,31): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(61,30,61,31): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(57,32,57,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(61,32,61,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(57,34,57,35): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(61,34,61,35): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(58,30,58,31): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float32'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(62,30,62,31): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float32'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(58,32,58,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float32'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(62,32,62,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float32'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(58,34,58,35): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float32'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(62,34,62,35): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float32'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(58,36,58,37): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float32'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(62,36,62,37): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float32'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(59,22,59,43): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(63,22,63,43): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(60,28,60,49): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(64,28,64,49): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(60,50,60,71): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(64,50,64,71): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(64,22,64,25): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(68,22,68,25): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(64,22,64,25): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(68,22,68,25): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(65,26,65,29): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(69,26,69,29): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(65,26,65,29): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(69,26,69,29): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(89,18,89,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(93,18,93,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(89,18,89,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(93,18,93,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(95,20,95,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(99,20,99,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(95,20,95,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(99,20,99,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(112,20,112,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(116,20,116,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(117,19,117,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(121,19,121,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(117,19,117,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(121,19,121,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(118,19,118,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(122,19,122,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(118,22,118,23): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(122,22,122,23): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(123,19,123,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'double'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(127,19,127,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'double'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(123,19,123,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'double'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(127,19,127,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'double'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(124,19,124,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'double'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(128,19,128,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'double'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(124,22,124,23): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'double'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(128,22,128,23): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'double'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(131,18,131,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(135,18,135,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(136,18,136,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(140,18,140,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(141,18,141,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'decimal'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(145,18,145,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'decimal'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(143,18,143,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'decimal'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(147,18,147,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'decimal'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(145,39,145,41): typecheck error FS3386: This expression uses an implicit conversion to convert type 'string' to type 'Xml.Linq.XNamespace'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(149,39,149,41): typecheck error FS3386: This expression uses an implicit conversion to convert type 'string' to type 'Xml.Linq.XNamespace'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(150,18,150,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'string' to type 'Xml.Linq.XNamespace'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(154,18,154,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'string' to type 'Xml.Linq.XNamespace'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(155,18,155,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'string' to type 'Xml.Linq.XName'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(159,18,159,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'string' to type 'Xml.Linq.XName'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(161,18,161,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(165,18,165,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(168,18,168,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'Y' to type 'X'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(172,18,172,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'Y' to type 'X'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(168,18,168,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'Y' to type 'X'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(172,18,172,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'Y' to type 'X'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(174,20,174,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(178,20,178,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(176,15,176,16): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(180,15,180,16): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(182,27,182,28): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'Nullable'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(186,27,186,28): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'Nullable'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(184,15,184,16): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'Nullable'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(188,15,188,16): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'Nullable'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(284,7,284,22): typecheck error FS0001: This expression was expected to have type +test.fsx(315,7,315,22): typecheck error FS0001: This expression was expected to have type 'unit' but here has type 'obj' -test.fsx(286,32,286,35): typecheck error FS0193: Type constraint mismatch. The type +test.fsx(317,32,317,35): typecheck error FS0193: Type constraint mismatch. The type 'float' is not compatible with type 'int' diff --git a/tests/fsharp/core/auto-widen/preview/test.fsx b/tests/fsharp/core/auto-widen/preview/test.fsx index ceb2a980cb1..331c3ae9d0b 100644 --- a/tests/fsharp/core/auto-widen/preview/test.fsx +++ b/tests/fsharp/core/auto-widen/preview/test.fsx @@ -48,7 +48,11 @@ module BasicTypeDirectedConversionsForFuncReturn = 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 @@ -184,95 +188,122 @@ module ConvertViaNullable = let x = f 2 let annotations = - let _ : obj = (1,2) - let _ : obj * obj = (1,2) + let v1 : obj = (1,2) + let v2 : obj * obj = (1,2) // structure through let - let _ : (obj * obj) = (let x = 1 in let y = 2 in (x,y)) + let v3 : (obj * obj) = (let x = 1 in let y = 2 in (x,y)) // structure through let rec - let _ : (obj * obj) = (let rec f x = x in (3,4.0)) + let v4 : (obj * obj) = (let rec f x = x in (3,4.0)) // structure through sequence - let _ : (obj * obj) = (); (3,4.0) + let v5 : (obj * obj) = (); (3,4.0) // struct tuple - let _ : struct (obj * obj) = struct (1,2) + let v6 : struct (obj * obj) = struct (1,2) // record (both field and overall result) - // let _ : obj = { F1 = (1, 2) } // TODO + 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 _ : {| A: obj |} = {| A = 1 |} + let v15 : {| A: obj |} = {| A = 1 |} // lambda return - let _ : (unit -> obj) = (fun () -> 1) + let v16 : (unit -> obj) = (fun () -> 1) // function lambda return - let _ : (int -> obj) = (function 1 -> 1 | 2 -> 3.0 | _ -> 4uy) + let v17 : (int -> obj) = (function 1 -> 1 | 2 -> 3.0 | _ -> 4uy) - let _ : (unit -> obj * obj) = (fun () -> (1,2)) + let v18 : (unit -> obj * obj) = (fun () -> (1,2)) // constants (1 :> System.IComparable) |> ignore - let _ : System.IComparable = 1 + let v19 : System.IComparable = 1 // array constants - let _ : System.Array = [| 1us |] + let v20 : System.Array = [| 1us |] - let _ : System.Array = [| 1I |] + let v21 : System.Array = [| 1I |] - let _ : System.IComparable = 1I + let v22 : System.IComparable = 1I // property - let _ : System.IComparable = System.String.Empty + let v23 : System.IComparable = System.String.Empty // method - let _ : System.IComparable = System.String.Format("") + let v24 : System.IComparable = System.String.Format("") - let _ : obj = System.String.Format("") + let v25 : obj = System.String.Format("") - let _ : System.IComparable = System.String.Format("") + let v26 : System.IComparable = System.String.Format("") // array constants - let _ : obj[] = [| 1 |] - let _ : (obj * obj)[] = [| (1,1) |] - let _ : (obj * obj)[] = [| ("abc",1) |] - let _ : (string * obj)[] = [| ("abc",1) |] - let _ : (string * obj)[] = [| ("abc",1); ("abc",3.0) |] - let _ : (string * obj)[] = [| Unchecked.defaultof<_>; ("abc",3.0) |] - let _ : struct (string * obj)[] = [| Unchecked.defaultof<_>; struct ("abc",3.0) |] - - let _ : obj = 1 - let _ : obj = (1 : int) - let _ : obj = "" - let _ : obj = ("" : string) - let _ : obj = ("" : System.IComparable) - let _ : obj = ("" : _) - let _ : obj = ("" : obj) - let _ : obj = { new System.ICloneable with member x.Clone() = obj() } - let _ : obj = "" - let _ : obj = string "" - let _ : obj = id "" + 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 _ : obj = if true then 1 else 3.0 - let _ : obj = (if true then 1 else 3.0) - let _ : obj = (if true then 1 elif true then 2uy else 3.0) + 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 _ : obj = try 1 with _ -> 3.0 + let v48 : obj = try 1 with _ -> 3.0 // try-finally - let _ : obj = try 1 finally () + let v49 : obj = try 1 finally () // match - let _ : obj = match true with true -> 1 | _ -> 3.0 + let v50 : obj = match true with true -> 1 | _ -> 3.0 () let f1 () : obj = 1 From 9c46f9967b1c073449245ec911e7a3bb1a020570 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 28 Jan 2021 17:04:00 +0000 Subject: [PATCH 24/42] ignore hanging test for now --- .../LegacyLanguageService/Tests.LanguageService.Completion.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs b/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs index af3a35a80fe..2597ece5745 100644 --- a/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs +++ b/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs @@ -3927,6 +3927,7 @@ let x = query { for bbbb in abbbbc(*D0*) do [ "Chars" ] // should not contain (documenting the undesirable behavior, that this does not show up) [] + [] member public this.``BY_DESIGN.ExplicitlyCloseTheParens.Bug73940``() = AssertAutoCompleteContains [ @" From e0db898ab205b3cb955e62cf182d076c67b56045 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Thu, 28 Jan 2021 17:13:27 +0000 Subject: [PATCH 25/42] fix hang --- src/fsharp/CheckExpressions.fs | 2 +- .../LegacyLanguageService/Tests.LanguageService.Completion.fs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index de8d5182f48..d6abb2ebb64 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -7474,7 +7474,7 @@ and TcDelayed cenv (overallTy: OverallTy) env tpenv mExpr expr exprty (atomicFla | [] | DelayedDot :: _ -> // at the end of the application chain allow coercion introduction - UnifyOverallTypeAndRecover cenv env mExpr overallTy exprty + UnifyOverallType cenv env mExpr overallTy exprty let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g let expr2 = AdjustExprForTypeDirectedConversions tcVal cenv.g cenv.amap cenv.infoReader env.AccessRights overallTy.Commit exprty mExpr expr.Expr expr2, tpenv diff --git a/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs b/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs index 2597ece5745..4a35de47ee9 100644 --- a/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs +++ b/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs @@ -3927,7 +3927,7 @@ let x = query { for bbbb in abbbbc(*D0*) do [ "Chars" ] // should not contain (documenting the undesirable behavior, that this does not show up) [] - [] + //[] member public this.``BY_DESIGN.ExplicitlyCloseTheParens.Bug73940``() = AssertAutoCompleteContains [ @" From b5feadf3ee597730bd72d75f5e4f2c0d81277d30 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sat, 30 Jan 2021 00:11:53 +0000 Subject: [PATCH 26/42] update baseline --- tests/fsharp/typeProviders/negTests/neg1.bsl | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/fsharp/typeProviders/negTests/neg1.bsl b/tests/fsharp/typeProviders/negTests/neg1.bsl index 3710102af10..8572d60442e 100644 --- a/tests/fsharp/typeProviders/negTests/neg1.bsl +++ b/tests/fsharp/typeProviders/negTests/neg1.bsl @@ -1638,22 +1638,16 @@ neg1.fsx(438,109,438,110): typecheck error FS0001: This expression was expected but here has type 'string' -neg1.fsx(438,9,438,111): typecheck error FS3033: The type provider 'Provider.GoodProviderForNegativeStaticParameterTypeTests' reported an error: Specified cast is not valid. - neg1.fsx(440,119,440,120): typecheck error FS0001: This expression was expected to have type 'int' but here has type 'string' -neg1.fsx(440,19,440,121): typecheck error FS3033: The type provider 'Provider.GoodProviderForNegativeStaticParameterTypeTests' reported an error: Specified cast is not valid. - neg1.fsx(440,119,440,120): typecheck error FS0001: This expression was expected to have type 'int' but here has type 'string' -neg1.fsx(440,19,440,121): typecheck error FS3033: The type provider 'Provider.GoodProviderForNegativeStaticParameterTypeTests' reported an error: Specified cast is not valid. - neg1.fsx(448,9,448,107): typecheck error FS3148: Too many static parameters. Expected at most 1 parameters, but got 2 unnamed and 0 named parameters. neg1.fsx(449,105,449,110): typecheck error FS3083: The static parameter 'Count' has already been given a value From 19ed0e64ed23dc8c92ecb0f79f8a9fc31521f168 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 25 May 2021 12:08:12 +0100 Subject: [PATCH 27/42] trim trailing spaces --- src/fsharp/CheckExpressions.fs | 410 ++++++++++++++++----------------- 1 file changed, 204 insertions(+), 206 deletions(-) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index d51723bb72a..ce932d9fade 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -403,15 +403,15 @@ type TcFileState = conditionalDefines: string list option isInternalTestSpanStackReferring: bool - // forward call + // forward call TcSequenceExpressionEntry: TcFileState -> TcEnv -> OverallTy -> UnscopedTyparEnv -> bool * bool ref * SynExpr -> range -> Expr * UnscopedTyparEnv - // forward call + // forward call TcArrayOrListSequenceExpression: TcFileState -> TcEnv -> OverallTy -> UnscopedTyparEnv -> bool * SynExpr -> range -> Expr * UnscopedTyparEnv - // forward call + // forward call TcComputationExpression: TcFileState -> TcEnv -> OverallTy -> UnscopedTyparEnv -> range * Expr * TType * SynExpr -> Expr * UnscopedTyparEnv - } + } /// Create a new compilation environment static member Create @@ -456,7 +456,7 @@ let UnifyTypes cenv (env: TcEnv) m actualTy expectedTy = // If the overall type admits subsumption, and the original unify would have failed, // then allow subsumption. let UnifyOverallType cenv (env: TcEnv) m overallTy actualTy = - match overallTy with + match overallTy with | MustConvertTo(reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions -> let actualTy = tryNormalizeMeasureInType cenv.g actualTy let reqdTy = tryNormalizeMeasureInType cenv.g reqdTy @@ -465,12 +465,12 @@ let UnifyOverallType cenv (env: TcEnv) m overallTy actualTy = else // try adhoc type-directed conversions let reqdTy2, usesTDC, eqn = AdjustRequiredTypeForTypeDirectedConversions cenv.infoReader env.eAccessRights false reqdTy actualTy m - match eqn with + match eqn with | Some (ty1, ty2, msg) -> UnifyTypes cenv env m ty1 ty2 msg env.DisplayEnv | None -> () - match usesTDC with + match usesTDC with | TypeDirectedConversionUsed.Yes warn -> warning(warn env.DisplayEnv) | TypeDirectedConversionUsed.No -> () if AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m reqdTy2 actualTy then @@ -807,7 +807,7 @@ let TcConst cenv (overallTy: TType) m env c = | SynMeasure.Seq(mss, _) -> ProdMeasures (List.map tcMeasure mss) | SynMeasure.Anon _ -> error(Error(FSComp.SR.tcUnexpectedMeasureAnon(), m)) | SynMeasure.Var(_, m) -> error(Error(FSComp.SR.tcNonZeroConstantCannotHaveGenericUnit(), m)) - + let unif expected = UnifyTypes cenv env m overallTy expected let unifyMeasureArg iszero tcr c = @@ -5021,7 +5021,7 @@ and TcPat warnOnUpper cenv env topValInfo vFlags (tpenv, names, takenNames) ty p let activePatResTys = NewInferenceTypes apinfo.Names let activePatType = apinfo.OverallType cenv.g m ty activePatResTys - let delayed = activePatArgsAsSynExprs |> List.map (fun arg -> DelayedApp(ExprAtomicFlag.NonAtomic, arg, unionRanges (rangeOfLid longId) arg.Range)) + let delayed = activePatArgsAsSynExprs |> List.map (fun arg -> DelayedApp(ExprAtomicFlag.NonAtomic, arg, unionRanges (rangeOfLid longId) arg.Range)) 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)) @@ -5297,8 +5297,8 @@ and TcExprFlex cenv flex compat (desiredTy: TType) (env: TcEnv) tpenv (synExpr: let argty = NewInferenceType () if compat then (destTyparTy cenv.g argty).SetIsCompatFlex(true) - AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css synExpr.Range NoTrace desiredTy argty - let expr2, tpenv = TcExprFlex2 cenv argty env tpenv synExpr + AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css synExpr.Range NoTrace desiredTy argty + let expr2, tpenv = TcExprFlex2 cenv argty env tpenv synExpr let expr3 = mkCoerceIfNeeded cenv.g desiredTy argty expr2 expr3, tpenv else @@ -5315,9 +5315,9 @@ and TcExpr cenv ty (env: TcEnv) tpenv (expr: SynExpr) = TcExprNoRecover cenv ty env tpenv expr with e -> let m = expr.Range - // 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 + // 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.Commit mkThrow m ty.Commit (mkOne cenv.g m), tpenv @@ -5339,7 +5339,7 @@ and TcExprOfUnknownTypeThen cenv env tpenv expr delayed = let expr', tpenv = try TcExprThen cenv (MustEqual exprty) env tpenv expr delayed - with e -> + with e -> let m = expr.Range errorRecovery e m solveTypAsError cenv env.DisplayEnv m exprty @@ -5384,11 +5384,11 @@ and TryTcStmt cenv env tpenv synExpr = let hasTypeUnit = TryUnifyUnitTypeWithoutWarning cenv env m ty hasTypeUnit, expr, tpenv -/// 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. +/// 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: OverallTy) env tpenv synExpr delayed = - match synExpr with + match synExpr with | LongOrSingleIdent (isOpt, longId, altNameRefCellOpt, mLongId) -> if isOpt then errorR(Error(FSComp.SR.tcSyntaxErrorUnexpectedQMark(), mLongId)) @@ -5430,7 +5430,7 @@ and TcExprThen cenv (overallTy: 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 TcExprsWithFlexes 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) @@ -5452,7 +5452,7 @@ and TcExprUndelayedNoType cenv env tpenv synExpr: Expr * TType * _ = expr, overallTy, tpenv and TcExprLeafProtectExcept2 p cenv (overallTy: OverallTy) actualTy (env: TcEnv) canAdhoc m f = - match overallTy with + match overallTy with | MustConvertTo(reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && not (p reqdTy) -> // Note about the cases where canAdhoc=false: // Some constructs (list expressions etc) require placing the subtype constraint down @@ -5460,23 +5460,21 @@ and TcExprLeafProtectExcept2 p cenv (overallTy: OverallTy) actualTy (env: TcEnv) // // These do not support adhoc conversions // - // TBD: consider removing canAdhoc and program those cases separately - // // Note about the cases where canAdhoc=true: // // This assumes the processing of the construct is independent of overallTy, and we can just pass a type // variable then check for adhoc and subsumption conversions after. - if not canAdhoc then + if not canAdhoc then AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace reqdTy actualTy let expr, tpenv = f () - if canAdhoc then + if canAdhoc then let reqdTy2, usesTDC, eqn = AdjustRequiredTypeForTypeDirectedConversions cenv.infoReader env.eAccessRights false reqdTy actualTy m - match eqn with + match eqn with | Some (ty1, ty2, msg) -> UnifyTypes cenv env m ty1 ty2 msg env.DisplayEnv | None -> () - match usesTDC with + match usesTDC with | TypeDirectedConversionUsed.Yes warn -> warning(warn env.DisplayEnv) | TypeDirectedConversionUsed.No -> () AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace reqdTy2 actualTy @@ -5488,7 +5486,7 @@ and TcExprLeafProtectExcept2 p cenv (overallTy: OverallTy) actualTy (env: TcEnv) f () and TcExprLeafProtectExcept p cenv (overallTy: OverallTy) (env: TcEnv) canAdhoc m f = - match overallTy with + match overallTy with | MustConvertTo(reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && not (p reqdTy) -> let actualTy = NewInferenceType() TcExprLeafProtectExcept2 p cenv overallTy actualTy env canAdhoc m (fun () -> f actualTy) @@ -5503,10 +5501,10 @@ and TcExprLeafProtect2 cenv overallTy actualTy env canAdhoc m f = 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. + 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.Commit, env.AccessRights) let env = ShrinkContext env mWholeExprIncludingParentheses expr2.Range TcExpr cenv overallTy env tpenv expr2 @@ -5514,7 +5512,7 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = | SynExpr.DotIndexedGet _ | SynExpr.DotIndexedSet _ | SynExpr.TypeApp _ | SynExpr.Ident _ | SynExpr.LongIdent _ | SynExpr.App _ | SynExpr.DotGet _ -> error(Error(FSComp.SR.tcExprUndelayed(), synExpr.Range)) - | SynExpr.Const (SynConst.String (s, _, m), _) -> + | SynExpr.Const (SynConst.String (s, _, m), _) -> CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) TcConstStringExpr cenv overallTy env m tpenv s @@ -5525,7 +5523,7 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = TcInterpolatedStringExpr cenv overallTy env m tpenv parts - | SynExpr.Const (synConst, m) -> + | SynExpr.Const (synConst, m) -> CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) TcConstExpr cenv overallTy env m tpenv synConst @@ -5552,7 +5550,7 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = | SynExpr.MatchLambda (isExnMatch, mArg, clauses, spMatch, m) -> - let domainTy, resultTy = UnifyFunctionType None cenv env.DisplayEnv m overallTy.Commit // OPPORTUNITY: MustSubsumeSoft for range + 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 (MustConvertTo resultTy) envinner tpenv clauses @@ -5569,14 +5567,14 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = | SynExpr.Typed (synBodyExpr, synType, m) -> let tgtTy, tpenv = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synType UnifyOverallType cenv env m overallTy tgtTy - let bodyExpr, tpenv = TcExpr cenv (MustConvertTo tgtTy) env tpenv synBodyExpr + let bodyExpr, tpenv = TcExpr cenv (MustConvertTo tgtTy) env tpenv synBodyExpr let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g let bodyExpr2 = AdjustExprForTypeDirectedConversions tcVal cenv.g cenv.amap cenv.infoReader env.AccessRights overallTy.Commit tgtTy m bodyExpr bodyExpr2, tpenv // e :? ty | SynExpr.TypeTest (synInnerExpr, tgtTy, m) -> - let innerExpr, srcTy, tpenv = TcExprOfUnknownType cenv env tpenv synInnerExpr + let innerExpr, srcTy, tpenv = TcExprOfUnknownType cenv env tpenv synInnerExpr 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 @@ -5597,8 +5595,8 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = let tgtTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv tgtTy UnifyTypes cenv env m tgtTy overallTy.Commit tgtTy, tpenv - | SynExpr.InferredUpcast _ -> - overallTy.Commit, tpenv + | SynExpr.InferredUpcast _ -> + overallTy.Commit, tpenv | _ -> failwith "upcast" TcStaticUpcast cenv env.DisplayEnv m tgtTy srcTy let expr = mkCoerceExpr(innerExpr, tgtTy, m, srcTy) @@ -5628,33 +5626,33 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = | SynExpr.Lazy (synInnerExpr, m) -> let innerTy = NewInferenceType () UnifyTypes cenv env m overallTy.Commit (mkLazyTy cenv.g innerTy) - let innerExpr, tpenv = TcExpr cenv (MustEqual innerTy) env tpenv synInnerExpr + 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) -> - TcExprLeafProtectExcept (isAnyTupleTy cenv.g) cenv overallTy env true m (fun overallTy -> + | SynExpr.Tuple (isExplicitStruct, args, _, m) -> + TcExprLeafProtectExcept (isAnyTupleTy cenv.g) cenv overallTy env true 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 + let expr = mkAnyTupled cenv.g m tupInfo args' argTys expr, tpenv ) - | SynExpr.AnonRecd (isStruct, optOrigExpr, unsortedFieldExprs, mWholeExpr) -> - TcExprLeafProtectExcept (isAnonRecdTy cenv.g) cenv overallTy env true mWholeExpr (fun overallTy -> + | SynExpr.AnonRecd (isStruct, optOrigExpr, unsortedFieldExprs, mWholeExpr) -> + TcExprLeafProtectExcept (isAnonRecdTy cenv.g) cenv overallTy env true mWholeExpr (fun overallTy -> TcAnonRecdExpr cenv overallTy env tpenv (isStruct, optOrigExpr, unsortedFieldExprs, mWholeExpr) ) - | SynExpr.ArrayOrList (isArray, args, m) -> + | SynExpr.ArrayOrList (isArray, args, m) -> 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 - + // Note, allowing canAdhoc = true would disable subtype-based propagation from overallTy into checking of structure // - // For example + // For example // let x : A seq = [ B(); B() ] // let x : B seq = [ B(); B() ] // let x : A list = [ B(); B() ] @@ -5685,13 +5683,13 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = expr, tpenv ) - | SynExpr.New (superInit, synObjTy, arg, mNewExpr) -> + | SynExpr.New (superInit, synObjTy, arg, mNewExpr) -> let objTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.Use env tpenv synObjTy // For consistency, op_Implicit is effectively disabled for direct uses of 'new' expressions let canAdhoc = false - TcExprLeafProtect2 cenv overallTy objTy env canAdhoc mNewExpr (fun () -> + TcExprLeafProtect2 cenv overallTy objTy env canAdhoc mNewExpr (fun () -> TcNewExpr cenv env tpenv objTy (Some synObjTy.Range) superInit arg mNewExpr ) @@ -5700,20 +5698,20 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = // Note, allowing canAdhoc = true would disable subtype-based propagation from overallTy into checking of structure // - // For example + // 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 //not (AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy.Commit actualTy) - TcExprLeafProtect cenv overallTy env canAdhoc m (fun overallTy -> + TcExprLeafProtect cenv overallTy env canAdhoc m (fun overallTy -> TcObjectExpr cenv overallTy env tpenv (objTy, argopt, binds, extraImpls, mNewExpr, m) ) - - | SynExpr.Record (inherits, optOrigExpr, flds, mWholeExpr) -> + + | SynExpr.Record (inherits, optOrigExpr, flds, mWholeExpr) -> CallExprHasTypeSink cenv.tcSink (mWholeExpr, env.NameEnv, overallTy.Commit, env.AccessRights) - let requiresCtor = (GetCtorShapeCounter env = 1) // Get special expression forms for constructors + let requiresCtor = (GetCtorShapeCounter env = 1) // Get special expression forms for constructors let haveCtor = Option.isSome inherits TcExprLeafProtectExcept (fun ty -> requiresCtor || haveCtor || isRecdTy cenv.g ty) cenv overallTy env true mWholeExpr (fun overallTy -> TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr) @@ -5773,10 +5771,10 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = | 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) + let _, _, tpenv = suppressErrorReporting (fun () -> TcExprOfUnknownType cenv env tpenv e2) mkDefault(mAll, overallTy.Commit), tpenv - | SynExpr.ArbitraryAfterError (_debugStr, m) -> + | SynExpr.ArbitraryAfterError (_debugStr, m) -> //solveTypAsError cenv env.DisplayEnv m overallTy mkDefault(m, overallTy.Commit), tpenv @@ -5869,7 +5867,7 @@ and TcExprUndelayed cenv (overallTy: 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) -> - TcExprLeafProtect cenv overallTy env true m (fun overallTy -> + TcExprLeafProtect cenv overallTy env true m (fun overallTy -> 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 @@ -5886,9 +5884,9 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = UnifyTypes cenv env m overallTy returnTy Expr.Op (TOp.TraitCall traitInfo, [], args', m), tpenv ) - + | SynExpr.LibraryOnlyUnionCaseFieldGet (e1, c, n, m) -> - TcExprLeafProtect cenv overallTy env true m (fun overallTy -> + TcExprLeafProtect cenv overallTy env true m (fun overallTy -> 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)), @@ -5928,7 +5926,7 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = | SynExpr.Quote (oper, raw, ast, isFromQueryExpression, m) -> CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) - TcQuotationExpr cenv overallTy env tpenv (oper, raw, ast, isFromQueryExpression, m) + TcQuotationExpr cenv overallTy env tpenv (oper, raw, ast, isFromQueryExpression, m) | SynExpr.YieldOrReturn ((isTrueYield, _), _, m) | SynExpr.YieldOrReturnFrom ((isTrueYield, _), _, m) when isTrueYield -> @@ -5969,12 +5967,12 @@ and TcIteratedLambdas cenv isFirst (env: TcEnv) overallTy takenNames tpenv e = conditionallySuppressErrorReporting (not isFirst && synExprContainsError e) (fun () -> 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 -// .NET metadata. This means we manually typecheck 'e1' and look to see if it has a nominal type. We then -// do the right thing in each case. -and TcIndexerThen cenv env overallTy mWholeExpr mDot tpenv wholeExpr e1 indexArgs delayed = +// 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 +// .NET metadata. This means we manually typecheck 'e1' and look to see if it has a nominal type. We then +// do the right thing in each case. +and TcIndexerThen cenv env overallTy mWholeExpr mDot tpenv wholeExpr e1 indexArgs delayed = let ad = env.AccessRights let e1', e1ty, tpenv = TcExprOfUnknownType cenv env tpenv e1 @@ -6191,10 +6189,10 @@ and TcNewExpr cenv env tpenv objTy mObjTyOpt superInit arg mWholeExprOrObjTy = else 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 (MustEqual objTy) objTy mObjTyOpt item superInit [arg] mWholeExprOrObjTy [] None -/// Check an 'inheritedTys declaration in an implicit or explicit class +/// Check an 'inheritedTys declaration in an implicit or explicit class 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) @@ -6232,7 +6230,7 @@ and TcCtorCall isNaked cenv env tpenv (overallTy: OverallTy) objTy mObjTyOpt ite | _ -> error(Error(FSComp.SR.tcSyntaxCanOnlyBeUsedToCreateObjectTypes(if superInit then "inherit" else "new"), mWholeCall)) -// Check a record construction expression +// Check a record construction expression and TcRecordConstruction cenv (overallTy: TType) env tpenv optOrigExprInfo objTy fldsList m = let tcref, tinst = destAppTy cenv.g objTy let tycon = tcref.Deref @@ -6546,9 +6544,9 @@ and CheckSuperType cenv ty m = error(Error(FSComp.SR.tcPredefinedTypeCannotBeUsedAsSuperType(), m)) if isErasedType cenv.g ty then errorR(Error(FSComp.SR.tcCannotInheritFromErasedType(), m)) - - -and TcObjectExpr cenv (overallTy: TType) env tpenv (synObjTy, argopt, binds, extraImpls, mNewExpr, mWholeExpr) = + + +and TcObjectExpr cenv (overallTy: TType) env tpenv (synObjTy, argopt, binds, extraImpls, mNewExpr, mWholeExpr) = let mObjTy = synObjTy.Range let objTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synObjTy @@ -6609,7 +6607,7 @@ and TcObjectExpr cenv (overallTy: TType) env tpenv (synObjTy, argopt, binds, ext let afterResolution = ForNewConstructors cenv.tcSink env synObjTy.Range methodName minfos let ad = env.AccessRights - let expr, tpenv = TcMethodApplicationThen cenv env (MustEqual 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 @@ -6679,10 +6677,10 @@ and TcObjectExpr cenv (overallTy: TType) env tpenv (synObjTy, argopt, binds, ext // TcConstStringExpr //------------------------------------------------------------------------- -/// Check a constant string expression. It might be a 'printf' format string +/// Check a constant string expression. It might be a 'printf' format string and TcConstStringExpr cenv (overallTy: OverallTy) env m tpenv s = - if (AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy.Commit 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 @@ -6719,7 +6717,7 @@ and TcFormatStringExpr cenv (overallTy: OverallTy) env m tpenv (fmtString: strin let fmtExpr = mkCallNewFormat g m aty bty cty dty ety (mkString g m fmtString) fmtExpr, tpenv - else + else TcExprLeafProtect2 cenv overallTy g.string_ty env true m (fun () -> mkString g m fmtString, tpenv ) @@ -6759,7 +6757,7 @@ and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: Syn 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.Commit 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 @@ -6772,9 +6770,9 @@ and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: Syn Choice1Of2 (true, newFormatMethod) // ... or if that fails then may be a FormattableString by a type-directed rule.... - 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 + 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 @@ -6793,7 +6791,7 @@ and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: Syn | 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.Commit) && AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy.Commit 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 @@ -6898,7 +6896,7 @@ and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: Syn // FormattableString are *always* turned into FormattableStringFactory.Create calls, boxing each argument let createExpr, _ = BuildPossiblyConditionalMethodCall cenv env NeverMutates m false createFormattableStringMethod NormalValUse [] [dotnetFormatStringExpr; argsExpr] [] - let resultExpr = + let resultExpr = if typeEquiv g overallTy.Commit g.system_IFormattable_ty then mkCoerceIfNeeded g g.system_IFormattable_ty g.system_FormattableString_ty createExpr else @@ -6909,18 +6907,18 @@ and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: Syn // TcConstExpr //------------------------------------------------------------------------- -/// Check a constant expression. +/// Check a constant expression. and TcConstExpr cenv (overallTy: OverallTy) env m tpenv c = - match c with + match c with - // NOTE: these aren't "really" constants - | SynConst.Bytes (bytes, _, m) -> - TcExprLeafProtect cenv overallTy env true m <| fun overallTy -> - UnifyTypes cenv env m overallTy (mkByteArrayTy cenv.g) + // NOTE: these aren't "really" constants + | SynConst.Bytes (bytes, _, m) -> + TcExprLeafProtect cenv overallTy env true m <| fun overallTy -> + UnifyTypes cenv env m overallTy (mkByteArrayTy cenv.g) Expr.Op (TOp.Bytes bytes, [], [], m), tpenv - | SynConst.UInt16s arr -> - TcExprLeafProtect cenv overallTy env true m <| fun overallTy -> + | SynConst.UInt16s arr -> + TcExprLeafProtect cenv overallTy env true m <| fun overallTy -> UnifyTypes cenv env m overallTy (mkArrayType cenv.g cenv.g.uint16_ty) Expr.Op (TOp.UInt16s arr, [], [], m), tpenv @@ -6956,8 +6954,8 @@ and TcConstExpr cenv (overallTy: OverallTy) env m tpenv c = TcExpr cenv overallTy env tpenv expr - | _ -> - TcExprLeafProtect cenv overallTy env true m <| fun overallTy -> + | _ -> + TcExprLeafProtect cenv overallTy env true m <| fun overallTy -> let c' = TcConst cenv overallTy m env c Expr.Const (c', m, overallTy), tpenv @@ -6985,7 +6983,7 @@ and TcRecdExpr cenv (overallTy: TType) env tpenv (inherits, optOrigExpr, flds, m | Some (origExpr, _) -> match inherits with | Some (_, _, mInherits, _, _) -> error(Error(FSComp.SR.tcInvalidRecordConstruction(), mInherits)) - | None -> + | None -> let olde, tpenv = TcExpr cenv (MustEqual overallTy) env tpenv origExpr Some (olde), tpenv @@ -7043,7 +7041,7 @@ and TcRecdExpr cenv (overallTy: TType) env tpenv (inherits, optOrigExpr, flds, m let superTy, tpenv = 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. + // Constructor expression, with an explicit 'inheritedTys clause. Check the inherits clause. let e, tpenv = TcExpr cenv (MustEqual realSuperTy) env tpenv (SynExpr.New (true, superTy, arg, m)) Some e, tpenv | None, Some realSuperTy when requiresCtor -> @@ -7307,11 +7305,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) - [TClause(pat, None, TTarget(valsDefinedByMatching, bodyExpr, DebugPointForTarget.Yes), mForLoopStart)] - enumElemTy - overallTy.Commit + CompilePatternForMatch + cenv env enumSynExpr.Range pat.Range false IgnoreWithWarning (elemVar, [], None) + [TClause(pat, None, TTarget(valsDefinedByMatching, bodyExpr, DebugPointForTarget.Yes), mForLoopStart)] + enumElemTy + overallTy.Commit // Apply the fixup to bind the elemVar if needed let bodyExpr = bodyExprFixup elemVar bodyExpr @@ -7358,9 +7356,9 @@ and TcQuotationExpr cenv overallTy env tpenv (_oper, raw, ast, isFromQueryExpres // Assert the overall type for the domain of the quotation template 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 (MustEqual astTy) env tpenv ast - + // Check the expression + let expr, tpenv = TcExpr cenv (MustEqual astTy) env tpenv ast + // Wrap the expression let expr = Expr.Quote (expr, ref None, isFromQueryExpression, m, overallTy.Commit) @@ -7380,8 +7378,8 @@ 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: OverallTy) (env: TcEnv) 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 | [] -> @@ -7395,7 +7393,7 @@ and Propagate cenv (overallTy: OverallTy) (env: TcEnv) tpenv (expr: ApplicableEx 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.Commit then + if isByrefTy cenv.g overallTy.Commit then errorR(Error(FSComp.SR.tcByrefReturnImplicitlyDereferenced(), mExpr)) destByrefTy cenv.g exprty else @@ -7449,32 +7447,32 @@ and Propagate cenv (overallTy: OverallTy) (env: TcEnv) tpenv (expr: ApplicableEx propagate false delayed expr.Range exprty -and PropagateThenTcDelayed cenv (overallTy: 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: 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. if (atomicFlag = ExprAtomicFlag.Atomic) then CallExprHasTypeSink cenv.tcSink (mExpr, env.NameEnv, exprty, env.eAccessRights) - match delayed with - | [] - | DelayedDot :: _ -> + match delayed with + | [] + | DelayedDot :: _ -> // at the end of the application chain allow coercion introduction - UnifyOverallType cenv env mExpr overallTy exprty + UnifyOverallType cenv env mExpr overallTy exprty let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g let expr2 = AdjustExprForTypeDirectedConversions tcVal cenv.g cenv.amap cenv.infoReader env.AccessRights overallTy.Commit exprty 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 + // 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 | DelayedDotLookup (longId, mDotLookup) :: otherDelayed -> TcLookupThen cenv overallTy env tpenv mExpr expr.Expr exprty longId otherDelayed mDotLookup // f x @@ -7551,8 +7549,8 @@ and TcNameOfExpr cenv env tpenv (synArg: SynExpr) = | Item.DelegateCtor _ | Item.CtorGroup _ | Item.FakeInterfaceCtor _ -> false - | _ -> true) -> - let overallTy = match overallTyOpt with None -> MustEqual (NewInferenceType()) | Some t -> t + | _ -> true) -> + let overallTy = match overallTyOpt with None -> MustEqual (NewInferenceType()) | Some t -> t let _, _ = TcItemThen cenv overallTy env tpenv res delayed true | _ -> @@ -7625,7 +7623,7 @@ and TcNameOfExprResult cenv (lastIdent: Ident) m = // TcFunctionApplicationThen: Typecheck "expr x" + projections //------------------------------------------------------------------------- -and TcFunctionApplicationThen cenv (overallTy: 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 @@ -7650,7 +7648,7 @@ and TcFunctionApplicationThen cenv (overallTy: OverallTy) env tpenv mExprAndArg | ApplicableExpr(_, Expr.Op(TOp.Coerce, _, [SeqExpr cenv.g], _), _) -> true | _ -> false) | _ -> () - + let arg, tpenv = TcExprFlex2 cenv domainTy env tpenv synArg let exprAndArg, resultTy = buildApp cenv expr resultTy arg mExprAndArg TcDelayed cenv overallTy env tpenv mExprAndArg exprAndArg resultTy atomicFlag delayed @@ -7660,9 +7658,9 @@ and TcFunctionApplicationThen cenv (overallTy: OverallTy) env tpenv mExprAndArg match synArg with | SynExpr.CompExpr (false, _isNotNakedRefCell, comp, _m) -> 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.Commit, mFunExpr, mArg)) + TcDelayed cenv overallTy env tpenv mExprAndArg (MakeApplicableExprNoFlex cenv bodyOfCompExpr) (tyOfExpr cenv.g bodyOfCompExpr) ExprAtomicFlag.NonAtomic delayed + | _ -> + error (NotAFunction(denv, overallTy.Commit, mFunExpr, mArg)) //------------------------------------------------------------------------- // TcLongIdentThen: Typecheck "A.B.C.E.F ... " constructs @@ -7738,8 +7736,8 @@ and TcItemThen cenv (overallTy: OverallTy) env tpenv (tinstEnclosing, item, mIte // This is where the constructor is applied to an argument | ((DelayedApp (atomicFlag, (FittedArgs args as origArg), mExprAndArg)) :: otherDelayed) -> // assert the overall result type if possible - if isNil otherDelayed then - UnifyOverallType cenv env mExprAndArg overallTy ucaseAppTy + if isNil otherDelayed then + UnifyOverallType cenv env mExprAndArg overallTy ucaseAppTy let numArgs = List.length args UnionCaseOrExnCheck env numArgTys numArgs mExprAndArg @@ -8184,7 +8182,7 @@ and TcItemThen cenv (overallTy: OverallTy) env tpenv (tinstEnclosing, item, mIte match delayed with | DelayedSet(e2, mStmt) :: otherDelayed -> if not (isNil otherDelayed) then error(Error(FSComp.SR.tcInvalidAssignment(), mStmt)) - // Static Property Set (possibly indexer) + // Static Property Set (possibly indexer) UnifyTypes cenv env mStmt overallTy.Commit g.unit_ty let meths = pinfos |> SettersOfPropInfos if meths.IsEmpty then @@ -8367,7 +8365,7 @@ and TcLookupThen cenv overallTy env tpenv mObjExpr objExpr objExprTy longId dela match delayed with | DelayedSet(e2, mStmt) :: otherDelayed -> if not (isNil otherDelayed) then error(Error(FSComp.SR.tcInvalidAssignment(), mStmt)) - // Instance property setter + // Instance property setter UnifyTypes cenv env mStmt overallTy.Commit cenv.g.unit_ty let meths = SettersOfPropInfos pinfos if meths.IsEmpty then @@ -8501,8 +8499,8 @@ and TcEventValueThen cenv overallTy env tpenv mItem mExprAndItem objDetails (ein and TcMethodApplicationThen cenv env - // 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 @@ -8525,8 +8523,8 @@ and TcMethodApplicationThen // Nb. args is always of List.length <= 1 except for indexed setters, when it is 2 let mWholeExpr = (m, args) ||> List.fold (fun m arg -> unionRanges m arg.Range) - // 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. + // 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 MustEqual (NewInferenceType ()) // Call the helper below to do the real checking @@ -8565,16 +8563,16 @@ and TcMethodApplication objArgs mMethExpr // range of the entire method expression mItem - methodName + methodName (objTyOpt: TType option) - ad - mut - isProp - calledMethsAndProps + ad + mut + isProp + calledMethsAndProps afterResolution - isSuperInit - curriedCallerArgs - (exprTy: OverallTy) + isSuperInit + curriedCallerArgs + (exprTy: OverallTy) delayed = @@ -8667,7 +8665,7 @@ and TcMethodApplication // The call lambda has function type let exprTy = mkFunTy (NewInferenceType ()) exprTy.Commit - + (None, Some unnamedCurriedCallerArgs.Head.Head, MustEqual exprTy) | _ -> @@ -8710,32 +8708,32 @@ and TcMethodApplication // no arguments are given or else based on the syntax of the arguments. let uniquelyResolved, preArgumentTypeCheckingCalledMethGroup = let dummyExpr = mkSynUnit mItem - - // Build the CallerArg values for the caller's arguments. - // Fake up some arguments if this is the use of a method as a first class function - let unnamedCurriedCallerArgs, namedCurriedCallerArgs, returnTy = - - match curriedCallerArgsOpt, candidates with - // "single named item" rule. This is where we have a single accessible method - // member x.M(arg1, ..., argN) - // being used in a first-class way, i.e. - // x.M - // Because there is only one accessible method info available based on the name of the item - // being accessed we know the number of arguments the first class use of this - // 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] -> + + // Build the CallerArg values for the caller's arguments. + // Fake up some arguments if this is the use of a method as a first class function + let unnamedCurriedCallerArgs, namedCurriedCallerArgs, returnTy = + + match curriedCallerArgsOpt, candidates with + // "single named item" rule. This is where we have a single accessible method + // member x.M(arg1, ..., argN) + // being used in a first-class way, i.e. + // x.M + // Because there is only one accessible method info available based on the name of the item + // being accessed we know the number of arguments the first class use of this + // 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.Commit calledMeth - let unnamedCurriedCallerArgs = curriedArgTys |> List.mapSquared (fun ty -> CallerArg(ty, mMethExpr, false, dummyExpr)) + let unnamedCurriedCallerArgs = curriedArgTys |> List.mapSquared (fun ty -> CallerArg(ty, mMethExpr, false, dummyExpr)) let namedCurriedCallerArgs = unnamedCurriedCallerArgs |> List.map (fun _ -> []) 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 - // this gives us the a potential number of arguments expected. Indeed even if it's a variable - // type we assume the number of arguments is just "1". + + // "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 + // this gives us the a potential number of arguments expected. Indeed even if it's a variable + // type we assume the number of arguments is just "1". | None, _ -> - + 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 @@ -8773,7 +8771,7 @@ and TcMethodApplication yield makeOneCalledMeth (minfo, pinfoOpt, false) ] let uniquelyResolved = - UnifyUniqueOverloading denv cenv.css mMethExpr callerArgCounts methodName ad preArgumentTypeCheckingCalledMethGroup returnTy + UnifyUniqueOverloading denv cenv.css mMethExpr callerArgCounts methodName ad preArgumentTypeCheckingCalledMethGroup returnTy uniquelyResolved, preArgumentTypeCheckingCalledMethGroup @@ -8784,20 +8782,20 @@ and TcMethodApplication // no arguments are given or else based on the syntax of the arguments. match curriedCallerArgsOpt with | None -> - let curriedArgTys, returnTy = - match candidates with - // "single named item" rule. This is where we have a single accessible method - // member x.M(arg1, ..., argN) - // being used in a first-class way, i.e. - // x.M - // Because there is only one accessible method info available based on the name of the item - // being accessed we know the number of arguments the first class use of this - // 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] -> + let curriedArgTys, returnTy = + match candidates with + // "single named item" rule. This is where we have a single accessible method + // member x.M(arg1, ..., argN) + // being used in a first-class way, i.e. + // x.M + // Because there is only one accessible method info available based on the name of the item + // being accessed we know the number of arguments the first class use of this + // 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] -> let curriedArgTys, returnTy = UnifyMatchingSimpleArgumentTypes exprTy.Commit calledMeth curriedArgTys, MustEqual returnTy - | _ -> + | _ -> 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 @@ -8807,7 +8805,7 @@ and TcMethodApplication else [domainTy] [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)) let namedCurriedCallerArgs = lambdaVarsAndExprs |> List.map (fun _ -> []) @@ -8821,9 +8819,9 @@ and TcMethodApplication let namedCurriedCallerArgs = namedCurriedCallerArgs |> List.mapSquared (fun (id, isOpt, argExpr, argTy, mArg) -> CallerNamedArg(id, CallerArg(argTy, mArg, isOpt, argExpr))) // Collect the information for F# 3.1 lambda propagation rule, and apply the caller's object type to the method's object type if the rule is relevant. - let lambdaPropagationInfo = - if preArgumentTypeCheckingCalledMethGroup.Length > 1 then - [| for meth in preArgumentTypeCheckingCalledMethGroup do + let lambdaPropagationInfo = + if preArgumentTypeCheckingCalledMethGroup.Length > 1 then + [| for meth in preArgumentTypeCheckingCalledMethGroup do match ExamineMethodForLambdaPropagation meth ad with | Some (unnamedInfo, namedInfo) -> let calledObjArgTys = meth.CalledObjArgTys mMethExpr @@ -8911,7 +8909,7 @@ and TcMethodApplication | AfterResolution.RecordResolution(_, _, _, onFailure), None -> onFailure() - // Raise the errors from the constraint solving + // Raise the errors from the constraint solving RaiseOperationResult errors match result with | None -> error(InternalError("at least one error should be returned by failed method overloading", mItem)) @@ -8978,12 +8976,12 @@ and TcMethodApplication BuildPossiblyConditionalMethodCall cenv env mut mMethExpr isProp finalCalledMethInfo isSuperInit finalCalledMethInst objArgs allArgsCoerced // Handle byref returns - let callExpr1, exprty = - // byref-typed returns get implicitly dereferenced + let callExpr1, exprty = + // byref-typed returns get implicitly dereferenced let vty = tyOfExpr cenv.g callExpr0 - if isByrefTy cenv.g vty then + if isByrefTy cenv.g vty then mkDerefAddrExpr mMethExpr callExpr0 mMethExpr vty, destByrefTy cenv.g vty - else + else callExpr0, exprty // Bind "out" parameters as part of the result tuple @@ -9001,20 +8999,20 @@ and TcMethodApplication expr, tyOfExpr cenv.g expr // Subsumption or conversion to return type - let callExpr2b = + let callExpr2b = let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g AdjustExprForTypeDirectedConversions tcVal cenv.g cenv.amap cenv.infoReader env.AccessRights returnTy.Commit exprty mMethExpr callExpr2 - // Handle post-hoc property assignments - let setterExprPrebinders, callExpr3 = + // Handle post-hoc property assignments + let setterExprPrebinders, callExpr3 = let expr = callExpr2b - if isCheckingAttributeCall then - [], expr - elif isNil finalAssignedItemSetters then - [], expr - else - // This holds the result of the call - let objv, objExpr = mkMutableCompGenLocal mMethExpr "returnVal" exprty // mutable in case it's a struct + if isCheckingAttributeCall then + [], expr + elif isNil finalAssignedItemSetters then + [], expr + else + // This holds the result of the call + let objv, objExpr = mkMutableCompGenLocal mMethExpr "returnVal" exprty // mutable in case it's a struct // Build the expression that mutates the properties on the result of the call let setterExprPrebinders, propSetExpr = @@ -9040,11 +9038,11 @@ and TcMethodApplication let callExpr5, tpenv = let expr = callExpr4 - match unnamedDelayedCallerArgExprOpt with - | Some synArgExpr -> - match lambdaVars with - | Some [lambdaVars] -> - let argExpr, tpenv = TcExpr cenv (MustEqual (mkRefTupledVarsTy cenv.g lambdaVars)) env tpenv synArgExpr + match unnamedDelayedCallerArgExprOpt with + | Some synArgExpr -> + match lambdaVars with + | Some [lambdaVars] -> + 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)) @@ -9084,7 +9082,7 @@ and TcSetterArgExpr cenv env denv objExpr ad (AssignedItemSetter(id, setter, Cal let calledArgTy = finfo.FieldType (cenv.amap, m) 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 + let action = BuildILFieldSet cenv.g m objExpr finfo argExpr argExprPrebinder, action, Item.ILField finfo | AssignedRecdFieldSetter rfinfo -> @@ -9093,7 +9091,7 @@ and TcSetterArgExpr cenv env denv objExpr ad (AssignedItemSetter(id, setter, Cal CheckRecdFieldMutation m denv rfinfo 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 + let action = BuildRecdFieldSet cenv.g m objExpr rfinfo argExpr argExprPrebinder, action, Item.RecdField rfinfo // Record the resolution for the Language Service @@ -9246,7 +9244,7 @@ and TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr expr cont = let mkf, envinner, tpenv = TcLetBinding cenv isUse env ExprContainerInfo ExpressionBinding tpenv (binds, m, body.Range) let envinner = ShrinkContext envinner m body.Range // tailcall - TcLinearExprs bodyChecker cenv envinner overallTy tpenv isCompExpr body (fun (x, tpenv) -> + TcLinearExprs bodyChecker cenv envinner overallTy tpenv isCompExpr body (fun (x, tpenv) -> cont (fst (mkf (x, overallTy.Commit)), tpenv)) | SynExpr.IfThenElse (synBoolExpr, synThenExpr, synElseExprOpt, spIfToThen, isRecovery, mIfToThen, m) when not isCompExpr -> @@ -9275,7 +9273,7 @@ and TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr expr cont = | Some synElseExpr -> let env = { env with eContextInfo = ContextInfo.ElseBranchResult synElseExpr.Range } // tailcall - TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr synElseExpr (fun (elseExpr, tpenv) -> + TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr synElseExpr (fun (elseExpr, tpenv) -> let resExpr = primMkCond spIfToThen DebugPointForTarget.Yes DebugPointForTarget.Yes m overallTy.Commit boolExpr thenExpr elseExpr cont (resExpr, tpenv)) @@ -9589,10 +9587,10 @@ 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 + if hasLiteralAttr then let literalValExpr, _ = TcExpr cenv (MustEqual overallTy) env tpenv synLiteralValExpr - match EvalLiteralExprOrAttribArg cenv.g literalValExpr with - | Expr.Const (c, _, ty) -> + match EvalLiteralExprOrAttribArg cenv.g literalValExpr with + | Expr.Const (c, _, ty) -> if c = Const.Zero && isStructTy cenv.g ty then warning(Error(FSComp.SR.tcIllegalStructTypeForConstantExpression(), synLiteralValExpr.Range)) false, None @@ -9736,7 +9734,7 @@ and TcAttribute canFail cenv (env: TcEnv) attrTgt (synAttr: SynAttribute) = | Item.CtorGroup(methodName, minfos) -> let meths = minfos |> List.map (fun minfo -> minfo, None) let afterResolution = ForNewConstructors cenv.tcSink env tyid.idRange methodName minfos - let (expr, attributeAssignedNamedItems, _), _ = + let (expr, attributeAssignedNamedItems, _), _ = 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) From 27e7911615b5aa3872bf01c12bcbd95e7ef657d9 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 25 May 2021 15:28:44 +0100 Subject: [PATCH 28/42] simplify expression leaf logic and make regular --- src/fsharp/CheckComputationExpressions.fs | 12 +- src/fsharp/CheckExpressions.fs | 243 ++++++++++++---------- src/fsharp/CheckExpressions.fsi | 5 + src/fsharp/ConstraintSolver.fs | 4 +- src/fsharp/LanguageFeatures.fs | 6 +- src/fsharp/LanguageFeatures.fsi | 2 +- src/fsharp/MethodCalls.fs | 20 +- 7 files changed, 163 insertions(+), 129 deletions(-) diff --git a/src/fsharp/CheckComputationExpressions.fs b/src/fsharp/CheckComputationExpressions.fs index b4d1f3b96e8..98ae6be7eea 100644 --- a/src/fsharp/CheckComputationExpressions.fs +++ b/src/fsharp/CheckComputationExpressions.fs @@ -214,7 +214,7 @@ let RecordNameAndTypeResolutions_IdeallyWithoutHavingOtherEffects cenv env tpenv /// Used for all computation expressions except sequence expressions let TcComputationExpression cenv env (overallTy: OverallTy) tpenv (mWhole, interpExpr: Expr, builderTy, comp: SynExpr) = - let overallTy = overallTy.Commit // TODO: a computation expression should be enough for MustConvertTo 'obj' etc. + let overallTy = overallTy.Commit //dprintfn "TcComputationExpression, comp = \n%A\n-------------------\n" comp let ad = env.eAccessRights @@ -1951,10 +1951,14 @@ 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 + 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 () -> + UnifyTypes cenv env m overallTy.Commit genCollTy let exprty = mkSeqTy cenv.g genCollElemTy @@ -1980,4 +1984,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/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index ce932d9fade..fb0b90ea9bc 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -453,11 +453,14 @@ let CopyAndFixupTypars m rigid tpsorig = let UnifyTypes cenv (env: TcEnv) m actualTy expectedTy = ConstraintSolver.AddCxTypeEqualsType env.eContextInfo env.DisplayEnv cenv.css m (tryNormalizeMeasureInType cenv.g actualTy) (tryNormalizeMeasureInType cenv.g expectedTy) -// If the overall type admits subsumption, and the original unify would have failed, -// then allow subsumption. +// 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(reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions -> + | MustConvertTo(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 @@ -5451,53 +5454,90 @@ and TcExprUndelayedNoType cenv env tpenv synExpr: Expr * TType * _ = let expr, tpenv = TcExprUndelayed cenv (MustEqual overallTy) env tpenv synExpr expr, overallTy, tpenv -and TcExprLeafProtectExcept2 p cenv (overallTy: OverallTy) actualTy (env: TcEnv) canAdhoc m f = +/// 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(reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && not (p reqdTy) -> - // Note about the cases where canAdhoc=false: - // Some constructs (list expressions etc) require placing the subtype constraint down - // before processing in order to propagate into the construct. - // - // These do not support adhoc conversions - // - // Note about the cases where canAdhoc=true: - // - // This assumes the processing of the construct is independent of overallTy, and we can just pass a type - // variable then check for adhoc and subsumption conversions after. - if not canAdhoc then - AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace reqdTy actualTy + | MustConvertTo(reqdTy) 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 (MustConvertTo reqdTy) actualTy + // Process the construct let expr, tpenv = f () - if canAdhoc then - let reqdTy2, usesTDC, eqn = AdjustRequiredTypeForTypeDirectedConversions cenv.infoReader env.eAccessRights 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 -> () - AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css m NoTrace reqdTy2 actualTy - let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g - let expr2 = AdjustExprForTypeDirectedConversions tcVal cenv.g cenv.amap cenv.infoReader env.AccessRights reqdTy actualTy m expr + // Build the conversion + let expr2 = TcAdjustExprForTypeDirectedConversions cenv overallTy actualTy env (* canAdhoc *) m expr expr2, tpenv | _ -> UnifyTypes cenv env m overallTy.Commit actualTy f () -and TcExprLeafProtectExcept p cenv (overallTy: OverallTy) (env: TcEnv) canAdhoc m 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.AdditionalImplicitConversions && not (p reqdTy) -> - let actualTy = NewInferenceType() - TcExprLeafProtectExcept2 p cenv overallTy actualTy env canAdhoc m (fun () -> f actualTy) + | 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) | _ -> - f overallTy.Commit - -and TcExprLeafProtect cenv overallTy env canAdhoc m f = - TcExprLeafProtectExcept (fun _ -> false) cenv overallTy env canAdhoc m f + // Here 'processExpr' will do the unification with the overall type. + processExpr overallTy.Commit -and TcExprLeafProtect2 cenv overallTy actualTy env canAdhoc m f = - TcExprLeafProtectExcept2 (fun _ -> false) cenv overallTy actualTy env canAdhoc m f +/// 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) = @@ -5568,8 +5608,7 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = let tgtTy, tpenv = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synType UnifyOverallType cenv env m overallTy tgtTy let bodyExpr, tpenv = TcExpr cenv (MustConvertTo tgtTy) env tpenv synBodyExpr - let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g - let bodyExpr2 = AdjustExprForTypeDirectedConversions tcVal cenv.g cenv.amap cenv.infoReader env.AccessRights overallTy.Commit tgtTy m bodyExpr + let bodyExpr2 = TcAdjustExprForTypeDirectedConversions cenv overallTy tgtTy env (* true *) m bodyExpr bodyExpr2, tpenv // e :? ty @@ -5631,7 +5670,7 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = expr, tpenv | SynExpr.Tuple (isExplicitStruct, args, _, m) -> - TcExprLeafProtectExcept (isAnyTupleTy cenv.g) cenv overallTy env true m (fun overallTy -> + 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) @@ -5641,7 +5680,7 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = ) | SynExpr.AnonRecd (isStruct, optOrigExpr, unsortedFieldExprs, mWholeExpr) -> - TcExprLeafProtectExcept (isAnonRecdTy cenv.g) cenv overallTy env true mWholeExpr (fun overallTy -> + TcPossiblyPropogatingExprLeafThenConvert (isAnonRecdTy cenv.g) cenv overallTy env mWholeExpr (fun overallTy -> TcAnonRecdExpr cenv overallTy env tpenv (isStruct, optOrigExpr, unsortedFieldExprs, mWholeExpr) ) @@ -5650,20 +5689,12 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = let argty = NewInferenceType () let actualTy = if isArray then mkArrayType cenv.g argty else mkListTy cenv.g argty - // Note, allowing canAdhoc = true would disable subtype-based propagation from overallTy into checking of structure - // - // For example - // let x : A seq = [ B(); B() ] - // let x : B seq = [ B(); B() ] - // let x : A list = [ B(); B() ] - // let x : B list = [ B(); B() ] - // but consider the case where there is no relation but an op_Implicit is enabled from List<_> to C + // 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() ] - // - // So op_Implicit is effectively disabled for direct uses of list expressions etc. - let canAdhoc = false //not (AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy.Commit actualTy) - TcExprLeafProtect2 cenv overallTy actualTy env canAdhoc m (fun () -> + 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) @@ -5686,14 +5717,11 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = | SynExpr.New (superInit, synObjTy, arg, mNewExpr) -> let objTy, tpenv = TcType cenv NewTyparsOK CheckCxs ItemOccurence.Use env tpenv synObjTy - // For consistency, op_Implicit is effectively disabled for direct uses of 'new' expressions - let canAdhoc = false - - TcExprLeafProtect2 cenv overallTy objTy env canAdhoc mNewExpr (fun () -> + 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) -> + | 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 @@ -5702,10 +5730,26 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = // 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 //not (AddCxTypeMustSubsumeTypeUndoIfFailed env.DisplayEnv cenv.css m overallTy.Commit actualTy) + //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 - TcExprLeafProtect cenv overallTy env canAdhoc m (fun overallTy -> - TcObjectExpr cenv overallTy env tpenv (objTy, argopt, binds, extraImpls, mNewExpr, m) + 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) -> @@ -5713,7 +5757,7 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = 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 - TcExprLeafProtectExcept (fun ty -> requiresCtor || haveCtor || isRecdTy cenv.g ty) cenv overallTy env true mWholeExpr (fun overallTy -> + TcPossiblyPropogatingExprLeafThenConvert (fun ty -> requiresCtor || haveCtor || isRecdTy cenv.g ty) cenv overallTy env mWholeExpr (fun overallTy -> TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr) ) @@ -5867,7 +5911,7 @@ and TcExprUndelayed cenv (overallTy: 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) -> - TcExprLeafProtect cenv overallTy env true m (fun overallTy -> + 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 @@ -5881,18 +5925,16 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = let flexes = argTys |> List.map (isTyparTy cenv.g >> not) 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) -> - TcExprLeafProtect cenv overallTy env true m (fun overallTy -> + 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) -> @@ -6546,17 +6588,15 @@ and CheckSuperType cenv ty m = errorR(Error(FSComp.SR.tcCannotInheritFromErasedType(), m)) -and TcObjectExpr cenv (overallTy: TType) 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 } @@ -6580,7 +6620,7 @@ and TcObjectExpr cenv (overallTy: TType) env tpenv (synObjTy, argopt, binds, ext | NormalizedBinding (_, _, _, _, [], _, _, _, SynPat.Named(SynPat.Wild _, 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) @@ -6588,23 +6628,13 @@ and TcObjectExpr cenv (overallTy: TType) env tpenv (synObjTy, argopt, binds, ext 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 + UnifyTypes cenv env mWholeExpr objTy 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 (MustEqual objTy) None tpenv None [] mWholeExpr mObjTy methodName ad PossiblyMutates false meths afterResolution CtorValUsedAsSuperInit [arg] ExprAtomicFlag.Atomic [] @@ -6624,15 +6654,13 @@ and TcObjectExpr cenv (overallTy: TType) env tpenv (synObjTy, argopt, binds, ext let baseValOpt = MakeAndPublishBaseVal cenv env baseIdOpt objTy let env = Option.foldBack (AddLocalVal cenv.tcSink mNewExpr) baseValOpt env - let impls = (mWholeExpr, objTy, binds) :: extraImpls - // 1. collect all the relevant abstract slots for each type we have to implement 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 @@ -6640,7 +6668,7 @@ and TcObjectExpr cenv (overallTy: TType) env tpenv (synObjTy, argopt, binds, ext 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' = @@ -6660,7 +6688,7 @@ and TcObjectExpr cenv (overallTy: TType) env tpenv (synObjTy, argopt, binds, ext 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')) @@ -6718,7 +6746,7 @@ and TcFormatStringExpr cenv (overallTy: OverallTy) env m tpenv (fmtString: strin fmtExpr, tpenv else - TcExprLeafProtect2 cenv overallTy g.string_ty env true m (fun () -> + TcPropagatingExprLeafThenConvert cenv overallTy g.string_ty env (* true *) m (fun () -> mkString g m fmtString, tpenv ) @@ -6874,8 +6902,8 @@ and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: Syn let fmtExpr = MakeMethInfoCall cenv.amap m newFormatMethod [] [mkString g m printfFormatString; argsExpr; percentATysExpr] if isString then - // Make the call to sprintf - TcExprLeafProtect2 cenv overallTy g.string_ty env true m (fun () -> + TcPropagatingExprLeafThenConvert cenv overallTy g.string_ty env (* true *) m (fun () -> + // Make the call to sprintf mkCall_sprintf g m printerTy fmtExpr [], tpenv ) else @@ -6911,15 +6939,14 @@ and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: Syn and TcConstExpr cenv (overallTy: OverallTy) env m tpenv c = match c with - // NOTE: these aren't "really" constants | SynConst.Bytes (bytes, _, m) -> - TcExprLeafProtect cenv overallTy env true m <| fun overallTy -> - 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 -> - TcExprLeafProtect cenv overallTy env true m <| fun overallTy -> - UnifyTypes cenv env m overallTy (mkArrayType cenv.g cenv.g.uint16_ty) + 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) -> @@ -6955,9 +6982,10 @@ and TcConstExpr cenv (overallTy: OverallTy) env m tpenv c = TcExpr cenv overallTy env tpenv expr | _ -> - TcExprLeafProtect cenv overallTy env true m <| fun overallTy -> - 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 @@ -7466,8 +7494,7 @@ and TcDelayed cenv (overallTy: OverallTy) env tpenv mExpr expr exprty (atomicFla | DelayedDot :: _ -> // at the end of the application chain allow coercion introduction UnifyOverallType cenv env mExpr overallTy exprty - let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g - let expr2 = AdjustExprForTypeDirectedConversions tcVal cenv.g cenv.amap cenv.infoReader env.AccessRights overallTy.Commit exprty mExpr expr.Expr + 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 @@ -8999,9 +9026,7 @@ and TcMethodApplication expr, tyOfExpr cenv.g expr // Subsumption or conversion to return type - let callExpr2b = - let tcVal = LightweightTcValForUsingInBuildMethodCall cenv.g - AdjustExprForTypeDirectedConversions tcVal cenv.g cenv.amap cenv.infoReader env.AccessRights returnTy.Commit exprty mMethExpr callExpr2 + let callExpr2b = TcAdjustExprForTypeDirectedConversions cenv returnTy exprty env mMethExpr callExpr2 // Handle post-hoc property assignments let setterExprPrebinders, callExpr3 = diff --git a/src/fsharp/CheckExpressions.fsi b/src/fsharp/CheckExpressions.fsi index 206f0e855c7..d677911ad01 100644 --- a/src/fsharp/CheckExpressions.fsi +++ b/src/fsharp/CheckExpressions.fsi @@ -661,6 +661,11 @@ val TcExprOfUnknownType: cenv:TcFileState -> env:TcEnv -> tpenv:UnscopedTyparEnv /// and insert a coercion if necessary. 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 diff --git a/src/fsharp/ConstraintSolver.fs b/src/fsharp/ConstraintSolver.fs index 762f95839ec..cb8796111d0 100644 --- a/src/fsharp/ConstraintSolver.fs +++ b/src/fsharp/ConstraintSolver.fs @@ -2355,7 +2355,7 @@ and CanMemberSigsMatchUpToCheck match reqdRetTyOpt with | Some _ when ( (* minfo.IsConstructor || *) not alwaysCheckReturn && isNil unnamedCalledOutArgs) -> ResultD TypeDirectedConversionUsed.No - | Some (MustConvertTo(reqdTy)) when g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions -> + | Some (MustConvertTo(reqdTy)) when g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions -> let methodRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling subsumeOrConvertTypes reqdTy methodRetTy | Some reqdRetTy -> @@ -2983,7 +2983,7 @@ and ResolveOverloading return! ErrorD(Error(FSComp.SR.tcByrefReturnImplicitlyDereferenced(), m)) else match reqdRetTy with - | MustConvertTo(reqdRetTy) when g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions -> + | MustConvertTo(reqdRetTy) when g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions -> let! _usesTDC = TypesMustSubsumeOrConvert csenv ad ndeep trace cxsln true m reqdRetTy actualRetTy return () | _ -> diff --git a/src/fsharp/LanguageFeatures.fs b/src/fsharp/LanguageFeatures.fs index 6934954153d..5b1a4017b4a 100644 --- a/src/fsharp/LanguageFeatures.fs +++ b/src/fsharp/LanguageFeatures.fs @@ -32,7 +32,7 @@ type LanguageFeature = | NullableOptionalInterop | DefaultInterfaceMemberConsumption | WitnessPassing - | AdditionalImplicitConversions + | AdditionalTypeDirectedConversions | InterfacesWithMultipleGenericInstantiation | StringInterpolation | OverloadsForCustomOperations @@ -75,7 +75,7 @@ type LanguageVersion (specifiedVersionAsString) = LanguageFeature.StringInterpolation, languageVersion50 // F# preview - LanguageFeature.AdditionalImplicitConversions, previewVersion + LanguageFeature.AdditionalTypeDirectedConversions, previewVersion LanguageFeature.OverloadsForCustomOperations, previewVersion LanguageFeature.ExpandedMeasurables, previewVersion LanguageFeature.FromEndSlicing, previewVersion @@ -148,7 +148,7 @@ type LanguageVersion (specifiedVersionAsString) = | LanguageFeature.NullableOptionalInterop -> FSComp.SR.featureNullableOptionalInterop() | LanguageFeature.DefaultInterfaceMemberConsumption -> FSComp.SR.featureDefaultInterfaceMemberConsumption() | LanguageFeature.WitnessPassing -> FSComp.SR.featureWitnessPassing() - | LanguageFeature.AdditionalImplicitConversions -> FSComp.SR.featureAdditionalImplicitConversions() + | 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 e8c30b7fbb2..a976148f036 100644 --- a/src/fsharp/LanguageFeatures.fsi +++ b/src/fsharp/LanguageFeatures.fsi @@ -20,7 +20,7 @@ type LanguageFeature = | NullableOptionalInterop | DefaultInterfaceMemberConsumption | WitnessPassing - | AdditionalImplicitConversions + | AdditionalTypeDirectedConversions | InterfacesWithMultipleGenericInstantiation | StringInterpolation | OverloadsForCustomOperations diff --git a/src/fsharp/MethodCalls.fs b/src/fsharp/MethodCalls.fs index 99a97de190d..a0e9c63c293 100644 --- a/src/fsharp/MethodCalls.fs +++ b/src/fsharp/MethodCalls.fs @@ -167,7 +167,7 @@ let AdjustDelegateTy (infoReader: InfoReader) actualTy reqdTy m = let TryFindRelevantImplicitConversion (infoReader: InfoReader) ad reqdTy actualTy m = let g = infoReader.g let amap = infoReader.amap - if g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && not (isTyparTy g actualTy) then + if g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && not (isTyparTy g actualTy) then let reqdTy2 = if isTyparTy g reqdTy then @@ -241,24 +241,24 @@ let rec AdjustRequiredTypeForTypeDirectedConversions (infoReader: InfoReader) ad AdjustRequiredTypeForTypeDirectedConversions infoReader ad isConstraint delegateTy actualTy m // Adhoc int32 --> int64 - elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.int64_ty reqdTy && typeEquiv g g.int32_ty actualTy then + 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), None // Adhoc int32 --> float32 - elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.float32_ty reqdTy && typeEquiv g g.int32_ty actualTy then + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.float32_ty reqdTy && typeEquiv g g.int32_ty actualTy then g.int32_ty, TypeDirectedConversionUsed.Yes(warn), None // Adhoc int32 --> float64 - elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.int32_ty actualTy then + 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), None // Adhoc float32--> float64 - elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.float32_ty actualTy then + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.float32_ty actualTy then g.float32_ty, TypeDirectedConversionUsed.Yes(warn), None // Adhoc based on op_Implicit, perhaps returing a new equational type constraint to // eliminate articifical constrained type variables. - elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions then + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions then match TryFindRelevantImplicitConversion infoReader ad reqdTy actualTy m with | Some (_minfo, eqn) -> actualTy, TypeDirectedConversionUsed.Yes(warn), Some eqn | None -> reqdTy, TypeDirectedConversionUsed.No, None @@ -1139,19 +1139,19 @@ let rec AdjustExprForTypeDirectedConversions tcVal (g: TcGlobals) amap infoReade mkCallQuoteToLinqLambdaExpression g m delegateTy (Expr.Quote (expr2, ref None, false, m, mkQuotedExprTy g delegateTy)) // Adhoc int32 --> int64 - elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.int64_ty reqdTy && typeEquiv g g.int32_ty actualTy then + 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 --> float32 - elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.float32_ty reqdTy && typeEquiv g g.int32_ty actualTy then + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.float32_ty reqdTy && typeEquiv g g.int32_ty actualTy then mkCallToSingleOperator g m actualTy expr // Adhoc int32 --> float64 - elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.int32_ty actualTy then + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.int32_ty actualTy then mkCallToDoubleOperator g m actualTy expr // Adhoc float32 --> float64 - elif g.langVersion.SupportsFeature LanguageFeature.AdditionalImplicitConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.float32_ty actualTy then + elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.float32_ty actualTy then mkCallToDoubleOperator g m actualTy expr else From 4e1e621cded787547816c7c24265a14fa73c15e6 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 25 May 2021 15:58:06 +0100 Subject: [PATCH 29/42] fix build --- src/fsharp/CheckExpressions.fs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index fb0b90ea9bc..80feb15d717 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -6627,9 +6627,6 @@ and TcObjectExpr cenv env tpenv (objTy, realObjTy, argopt, binds, extraImpls, mO if isFSharpObjModelTy cenv.g objTy && GetCtorShapeCounter env = 1 then error(Error(FSComp.SR.tcObjectsMustBeInitializedWithObjectExpression(), mNewExpr)) - // Work out the type of any interfaces to implement - UnifyTypes cenv env mWholeExpr objTy realObjTy - let ctorCall, baseIdOpt, tpenv = match item, argopt with | Item.CtorGroup(methodName, minfos), Some (arg, baseIdOpt) -> @@ -6694,6 +6691,7 @@ and TcObjectExpr cenv env tpenv (objTy, realObjTy, argopt, binds, extraImpls, mO (implty, overrides')) let (objTy', overrides') = allTypeImpls.Head + assert (typeEquiv cenv.g objTy objTy') let extraImpls = allTypeImpls.Tail // 7. Build the implementation From bf35f4010cfaab957c24f22983cfa2f8136efab4 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 25 May 2021 16:57:16 +0100 Subject: [PATCH 30/42] update testing --- src/fsharp/CheckComputationExpressions.fs | 2 - tests/fsharp/core/auto-widen/5.0/test.bsl | 558 +++++++++++++----- tests/fsharp/core/auto-widen/5.0/test.fsx | 291 +++++++-- tests/fsharp/core/auto-widen/preview/test.bsl | 97 ++- tests/fsharp/core/auto-widen/preview/test.fsx | 150 ++++- tests/fsharp/tests.fs | 5 + .../fsharp/typecheck/sigs/version50/neg20.bsl | 2 +- tests/service/ServiceUntypedParseTests.fs | 2 +- .../Tests.LanguageService.Completion.fs | 1 - 9 files changed, 898 insertions(+), 210 deletions(-) diff --git a/src/fsharp/CheckComputationExpressions.fs b/src/fsharp/CheckComputationExpressions.fs index 98ae6be7eea..9eb2b65f8b2 100644 --- a/src/fsharp/CheckComputationExpressions.fs +++ b/src/fsharp/CheckComputationExpressions.fs @@ -1959,8 +1959,6 @@ let TcArrayOrListSequenceExpression (cenv: cenv) env overallTy tpenv (isArray, c // let x : seq = [ yield 1; if true then yield 2 ] TcPropagatingExprLeafThenConvert cenv overallTy genCollTy env (* canAdhoc *) m (fun () -> - UnifyTypes cenv env m overallTy.Commit genCollTy - let exprty = mkSeqTy cenv.g genCollElemTy // Check the comprehension diff --git a/tests/fsharp/core/auto-widen/5.0/test.bsl b/tests/fsharp/core/auto-widen/5.0/test.bsl index 6455fed873d..c5f56d7234b 100644 --- a/tests/fsharp/core/auto-widen/5.0/test.bsl +++ b/tests/fsharp/core/auto-widen/5.0/test.bsl @@ -1,170 +1,170 @@ -test.fsx(8,20,8,21): typecheck error FS0001: This expression was expected to have type +test.fsx(11,20,11,21): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(11,20,11,41): typecheck error FS0001: This expression was expected to have type +test.fsx(14,20,14,41): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(14,20,14,44): typecheck error FS0001: This expression was expected to have type +test.fsx(17,20,17,44): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(17,21,17,24): typecheck error FS0001: This expression was expected to have type +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(25,31,25,32): typecheck error FS0001: This expression was expected to have type +test.fsx(28,31,28,32): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'string' -test.fsx(30,27,30,28): typecheck error FS0001: This expression was expected to have type +test.fsx(33,27,33,28): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(30,29,30,30): typecheck error FS0001: This expression was expected to have type +test.fsx(33,29,33,30): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(33,56,33,57): typecheck error FS0001: This expression was expected to have type +test.fsx(36,56,36,57): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(33,58,33,59): typecheck error FS0001: This expression was expected to have type +test.fsx(36,58,36,59): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(36,43,36,44): typecheck error FS0001: This expression was expected to have type +test.fsx(39,43,39,44): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(36,45,36,46): typecheck error FS0001: This expression was expected to have type +test.fsx(39,45,39,46): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(41,41,41,42): typecheck error FS0001: This expression was expected to have type +test.fsx(44,41,44,42): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(42,48,42,49): typecheck error FS0001: This expression was expected to have type +test.fsx(45,48,45,49): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(42,50,42,51): typecheck error FS0001: This expression was expected to have type +test.fsx(45,50,45,51): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(45,30,45,31): typecheck error FS0001: This expression was expected to have type +test.fsx(48,30,48,31): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(45,32,45,33): typecheck error FS0001: This expression was expected to have type +test.fsx(48,32,48,33): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(51,22,51,24): typecheck error FS0001: This expression was expected to have type +test.fsx(58,22,58,24): typecheck error FS0001: This expression was expected to have type 'int64' but here has type 'int' -test.fsx(52,22,52,23): typecheck error FS0001: This expression was expected to have type +test.fsx(59,22,59,23): typecheck error FS0001: This expression was expected to have type 'int64' but here has type 'int' -test.fsx(53,28,53,29): typecheck error FS0001: This expression was expected to have type +test.fsx(60,28,60,29): typecheck error FS0001: This expression was expected to have type 'int64' but here has type 'int' -test.fsx(53,30,53,31): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'int64'. This element has type 'int'. +test.fsx(60,30,60,31): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'int64'. This element has type 'int'. -test.fsx(53,32,53,33): typecheck error FS0001: All elements of a list must be of the same type as 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 of the same type as the first element, which here is 'int64'. This element has type 'int'. -test.fsx(53,34,53,35): typecheck error FS0001: All elements of a list must be of the same type as 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 of the same type as the first element, which here is 'int64'. This element has type 'int'. -test.fsx(54,28,54,29): typecheck error FS0001: This expression was expected to have type +test.fsx(61,28,61,29): typecheck error FS0001: This expression was expected to have type 'float' but here has type 'int' -test.fsx(54,30,54,31): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'float'. This element has type 'int'. +test.fsx(61,30,61,31): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'float'. This element has type 'int'. -test.fsx(54,32,54,33): typecheck error FS0001: All elements of a list must be of the same type as 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 of the same type as the first element, which here is 'float'. This element has type 'int'. -test.fsx(54,34,54,35): typecheck error FS0001: All elements of a list must be of the same type as 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 of the same type as the first element, which here is 'float'. This element has type 'int'. -test.fsx(55,30,55,31): typecheck error FS0001: This expression was expected to have type +test.fsx(62,30,62,31): typecheck error FS0001: This expression was expected to have type 'float32' but here has type 'int' -test.fsx(55,32,55,33): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'float32'. This element has type 'int'. +test.fsx(62,32,62,33): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'float32'. This element has type 'int'. -test.fsx(55,34,55,35): typecheck error FS0001: All elements of a list must be of the same type as 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 of the same type as the first element, which here is 'float32'. This element has type 'int'. -test.fsx(55,36,55,37): typecheck error FS0001: All elements of a list must be of the same type as 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 of the same type as the first element, which here is 'float32'. This element has type 'int'. -test.fsx(56,22,56,43): typecheck error FS0001: This expression was expected to have type +test.fsx(63,22,63,43): typecheck error FS0001: This expression was expected to have type 'int64' but here has type 'int' -test.fsx(57,28,57,49): typecheck error FS0001: This expression was expected to have type +test.fsx(64,28,64,49): typecheck error FS0001: This expression was expected to have type 'int64' but here has type 'int' -test.fsx(57,50,57,71): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'int64'. This element has type 'int'. +test.fsx(64,50,64,71): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'int64'. This element has type 'int'. -test.fsx(60,20,60,23): typecheck error FS0001: This expression was expected to have type +test.fsx(67,20,67,23): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(60,20,60,23): typecheck error FS0001: This expression was expected to have type +test.fsx(67,20,67,23): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(61,22,61,25): typecheck error FS0001: This expression was expected to have type +test.fsx(68,22,68,25): typecheck error FS0001: This expression was expected to have type 'int64' but here has type 'int' -test.fsx(61,22,61,25): typecheck error FS0001: This expression was expected to have type +test.fsx(68,22,68,25): typecheck error FS0001: This expression was expected to have type 'int64' but here has type 'int' -test.fsx(62,26,62,29): typecheck error FS0001: This expression was expected to have type +test.fsx(69,26,69,29): typecheck error FS0001: This expression was expected to have type 'int64' but here has type 'int' -test.fsx(62,26,62,29): typecheck error FS0001: This expression was expected to have type +test.fsx(69,26,69,29): typecheck error FS0001: This expression was expected to have type 'int64' but here has type 'int' -test.fsx(86,13,86,20): typecheck error FS0041: No overloads match for method 'M1'. +test.fsx(93,13,93,20): typecheck error FS0041: No overloads match for method 'M1'. Known type of argument: int @@ -172,7 +172,7 @@ 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(92,13,92,22): typecheck error FS0041: No overloads match for method 'M1'. +test.fsx(99,13,99,22): typecheck error FS0041: No overloads match for method 'M1'. Known type of argument: x:int @@ -180,12 +180,12 @@ 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(109,20,109,21): typecheck error FS0001: This expression was expected to have type +test.fsx(116,20,116,21): typecheck error FS0001: This expression was expected to have type 'int64' but here has type 'int' -test.fsx(114,14,114,21): typecheck error FS0041: No overloads match for method 'M1'. +test.fsx(121,14,121,21): typecheck error FS0041: No overloads match for method 'M1'. Known type of argument: int @@ -193,17 +193,17 @@ 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(115,19,115,20): typecheck error FS0001: This expression was expected to have type +test.fsx(122,19,122,20): typecheck error FS0001: This expression was expected to have type 'int64' but here has type 'int' -test.fsx(115,22,115,23): typecheck error FS0001: This expression was expected to have type +test.fsx(122,22,122,23): typecheck error FS0001: This expression was expected to have type 'int64' but here has type 'int' -test.fsx(120,14,120,21): typecheck error FS0041: No overloads match for method 'M1'. +test.fsx(127,14,127,21): typecheck error FS0041: No overloads match for method 'M1'. Known type of argument: int @@ -211,381 +211,669 @@ 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(121,19,121,20): typecheck error FS0001: This expression was expected to have type +test.fsx(128,19,128,20): typecheck error FS0001: This expression was expected to have type 'double' but here has type 'int' -test.fsx(121,22,121,23): typecheck error FS0001: This expression was expected to have type +test.fsx(128,22,128,23): typecheck error FS0001: This expression was expected to have type 'double' but here has type 'int' -test.fsx(128,18,128,19): typecheck error FS0001: This expression was expected to have type +test.fsx(135,18,135,19): typecheck error FS0001: This expression was expected to have type 'C' but here has type 'int' -test.fsx(133,18,133,19): typecheck error FS0001: This expression was expected to have type +test.fsx(140,18,140,19): typecheck error FS0001: This expression was expected to have type 'int64' but here has type 'int' -test.fsx(138,18,138,19): typecheck error FS0001: This expression was expected to have type +test.fsx(145,18,145,19): typecheck error FS0001: This expression was expected to have type 'decimal' but here has type 'int' -test.fsx(140,18,140,19): typecheck error FS0001: This expression was expected to have type +test.fsx(147,18,147,19): typecheck error FS0001: This expression was expected to have type 'decimal' but here has type 'int' -test.fsx(142,39,142,41): typecheck error FS0001: This expression was expected to have type +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(147,18,147,20): typecheck error FS0001: This expression was expected to have type +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(152,18,152,21): typecheck error FS0001: This expression was expected to have type +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(158,18,158,19): typecheck error FS0001: The type 'int' is not compatible with the type 'C' +test.fsx(165,18,165,19): typecheck error FS0001: The type 'int' is not compatible with the type 'C' -test.fsx(158,17,158,20): typecheck error FS0193: Type constraint mismatch. The type +test.fsx(165,17,165,20): typecheck error FS0193: Type constraint mismatch. The type 'int' is not compatible with type 'C' -test.fsx(165,18,165,21): typecheck error FS0001: The type 'Y' is not compatible with the type 'X' +test.fsx(172,18,172,21): typecheck error FS0001: The type 'Y' is not compatible with the type 'X' -test.fsx(165,17,165,22): typecheck error FS0193: Type constraint mismatch. The type +test.fsx(172,17,172,22): typecheck error FS0193: Type constraint mismatch. The type 'Y' is not compatible with type 'X' -test.fsx(171,20,171,21): typecheck error FS0001: This expression was expected to have type +test.fsx(178,20,178,21): typecheck error FS0001: This expression was expected to have type 'C' but here has type 'int' -test.fsx(173,15,173,16): typecheck error FS0001: The type 'int' is not compatible with the type 'C' +test.fsx(180,15,180,16): typecheck error FS0001: The type 'int' is not compatible with the type 'C' -test.fsx(179,27,179,28): typecheck error FS0001: This expression was expected to have type +test.fsx(186,27,186,28): typecheck error FS0001: This expression was expected to have type 'Nullable' but here has type 'int' -test.fsx(181,15,181,16): typecheck error FS0001: This expression was expected to have type +test.fsx(188,15,188,16): typecheck error FS0001: This expression was expected to have type 'Nullable' but here has type 'int' -test.fsx(184,20,184,23): typecheck error FS0001: This expression was expected to have type +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(185,26,185,27): typecheck error FS0001: This expression was expected to have type +test.fsx(192,27,192,28): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(185,28,185,29): typecheck error FS0001: This expression was expected to have type +test.fsx(192,29,192,30): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(188,55,188,56): typecheck error FS0001: This expression was expected to have type +test.fsx(195,56,195,57): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(188,57,188,58): typecheck error FS0001: This expression was expected to have type +test.fsx(195,58,195,59): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(191,48,191,49): typecheck error FS0001: This expression was expected to have type +test.fsx(198,49,198,50): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(191,50,191,53): typecheck error FS0001: This expression was expected to have type +test.fsx(198,51,198,54): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'float' -test.fsx(194,32,194,33): typecheck error FS0001: This expression was expected to have type +test.fsx(201,33,201,34): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(194,34,194,37): typecheck error FS0001: This expression was expected to have type +test.fsx(201,35,201,38): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'float' -test.fsx(197,42,197,43): typecheck error FS0001: This expression was expected to have type +test.fsx(204,43,204,44): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(197,44,197,45): typecheck error FS0001: This expression was expected to have type +test.fsx(204,45,204,46): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(203,13,203,14): typecheck error FS0001: This expression was expected to have type +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(203,16,203,19): typecheck error FS0001: This expression was expected to have type +test.fsx(237,16,237,19): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'byte' -test.fsx(203,30,203,33): typecheck error FS0001: This expression was expected to have type +test.fsx(237,30,237,33): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'float' -test.fsx(203,35,203,36): typecheck error FS0001: This expression was expected to have type +test.fsx(237,35,237,36): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(209,40,209,41): typecheck error FS0001: This expression was expected to have type +test.fsx(243,42,243,43): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(212,43,212,44): typecheck error FS0001: This expression was expected to have type +test.fsx(246,45,246,46): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(212,52,212,55): typecheck error FS0001: All branches of a pattern match expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. +test.fsx(246,54,246,57): typecheck error FS0001: All branches of a pattern match expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. -test.fsx(212,63,212,66): typecheck error FS0001: All branches of a pattern match expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'byte'. +test.fsx(246,65,246,68): typecheck error FS0001: All branches of a pattern match expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'byte'. -test.fsx(214,47,214,48): typecheck error FS0001: This expression was expected to have type +test.fsx(248,49,248,50): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(214,49,214,50): typecheck error FS0001: This expression was expected to have type +test.fsx(248,51,248,52): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(219,34,219,35): typecheck error FS0001: This expression was expected to have type +test.fsx(253,36,253,37): typecheck error FS0001: This expression was expected to have type 'IComparable' but here has type 'int' -test.fsx(222,28,222,37): typecheck error FS0001: This expression was expected to have type +test.fsx(256,30,256,39): typecheck error FS0001: This expression was expected to have type 'Array' but here has type 'uint16 []' -test.fsx(224,28,224,36): typecheck error FS0001: This expression was expected to have type +test.fsx(258,30,258,38): typecheck error FS0001: This expression was expected to have type 'Array' but here has type ''a []' -test.fsx(226,34,226,36): typecheck error FS0001: This expression was expected to have type +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(229,42,229,61): typecheck error FS0001: This expression was expected to have type +test.fsx(263,44,263,63): typecheck error FS0001: This expression was expected to have type 'IComparable' but here has type 'string' -test.fsx(232,42,232,66): typecheck error FS0001: This expression was expected to have type +test.fsx(266,44,266,68): typecheck error FS0001: This expression was expected to have type 'IComparable' but here has type 'string' -test.fsx(234,19,234,43): typecheck error FS0001: This expression was expected to have type +test.fsx(268,21,268,45): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'string' -test.fsx(236,34,236,58): typecheck error FS0001: This expression was expected to have type +test.fsx(270,36,270,60): typecheck error FS0001: This expression was expected to have type 'IComparable' but here has type 'string' -test.fsx(241,33,241,34): typecheck error FS0001: This expression was expected to have type +test.fsx(275,35,275,36): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(241,35,241,36): typecheck error FS0001: This expression was expected to have type +test.fsx(275,37,275,38): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(242,33,242,38): typecheck error FS0001: This expression was expected to have type +test.fsx(276,35,276,40): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'string' -test.fsx(242,39,242,40): typecheck error FS0001: This expression was expected to have type +test.fsx(276,41,276,42): 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 +test.fsx(277,44,277,45): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(244,42,244,43): typecheck error FS0001: This expression was expected to have type +test.fsx(278,44,278,45): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(244,53,244,56): typecheck error FS0001: This expression was expected to have type +test.fsx(278,55,278,58): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'float' -test.fsx(245,66,245,69): typecheck error FS0001: This expression was expected to have type +test.fsx(279,68,279,71): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'float' -test.fsx(246,80,246,83): typecheck error FS0001: This expression was expected to have type +test.fsx(280,82,280,85): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'float' -test.fsx(248,19,248,20): typecheck error FS0001: This expression was expected to have type +test.fsx(282,21,282,22): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(249,20,249,27): typecheck error FS0001: This expression was expected to have type +test.fsx(283,22,283,29): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(250,19,250,21): typecheck error FS0001: This expression was expected to have type +test.fsx(284,21,284,23): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'string' -test.fsx(251,20,251,31): typecheck error FS0001: This expression was expected to have type +test.fsx(285,22,285,33): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'string' -test.fsx(252,20,252,43): typecheck error FS0001: This expression was expected to have type +test.fsx(286,22,286,45): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'IComparable' -test.fsx(253,20,253,22): typecheck error FS0001: This expression was expected to have type +test.fsx(287,22,287,24): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'string' -test.fsx(254,20,254,22): typecheck error FS0001: This expression was expected to have type +test.fsx(288,22,288,24): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'string' -test.fsx(255,19,255,74): typecheck error FS0001: This expression was expected to have type +test.fsx(289,21,289,76): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'ICloneable' -test.fsx(256,19,256,21): typecheck error FS0001: This expression was expected to have type +test.fsx(290,21,290,23): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'string' -test.fsx(257,19,257,28): typecheck error FS0001: This expression was expected to have type +test.fsx(291,21,291,30): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'string' -test.fsx(257,19,257,28): typecheck error FS0001: This expression was expected to have type +test.fsx(291,21,291,30): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'string' -test.fsx(258,22,258,24): typecheck error FS0001: This expression was expected to have type +test.fsx(292,24,292,26): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'string' -test.fsx(261,32,261,33): typecheck error FS0001: The 'if' expression needs to have type 'obj' to satisfy context type requirements. It currently has type 'int'. +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(261,39,261,42): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. +test.fsx(295,41,295,44): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. -test.fsx(262,33,262,34): typecheck error FS0001: The 'if' expression needs to have type 'obj' to satisfy context type requirements. It currently has type 'int'. +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(262,40,262,43): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. +test.fsx(296,42,296,45): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. -test.fsx(263,33,263,34): typecheck error FS0001: The 'if' expression needs to have type 'obj' to satisfy context type requirements. It currently has type 'int'. +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(263,50,263,53): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'byte'. +test.fsx(297,52,297,55): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'byte'. -test.fsx(263,59,263,62): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. +test.fsx(297,61,297,64): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. -test.fsx(266,23,266,24): typecheck error FS0001: This expression was expected to have type +test.fsx(300,25,300,26): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(266,35,266,38): typecheck error FS0001: This expression was expected to have type +test.fsx(300,37,300,40): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'float' -test.fsx(269,23,269,24): typecheck error FS0001: This expression was expected to have type +test.fsx(303,25,303,26): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(272,43,272,44): typecheck error FS0001: This expression was expected to have type +test.fsx(306,45,306,46): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(272,52,272,55): typecheck error FS0001: All branches of a pattern match expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. +test.fsx(306,54,306,57): typecheck error FS0001: All branches of a pattern match expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. -test.fsx(275,19,275,20): typecheck error FS0001: This expression was expected to have type +test.fsx(309,19,309,20): typecheck error FS0001: This expression was expected to have type 'obj' but here has type 'int' -test.fsx(276,32,276,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,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(276,39,276,42): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. +test.fsx(310,39,310,42): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. -test.fsx(280,9,280,11): typecheck error FS0001: This expression was expected to have type - 'obj' +test.fsx(313,37,313,38): typecheck error FS0001: This expression was expected to have type + 'int64' but here has type - 'string' + 'int' -test.fsx(281,7,281,22): typecheck error FS0001: This expression was expected to have type - 'unit' +test.fsx(314,37,314,38): typecheck error FS0001: This expression was expected to have type + 'int64' but here has type - 'obj' + '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(283,32,283,35): typecheck error FS0001: All branches of an 'if' expression must return values of the same type as the first branch, which here is 'int'. This branch returns a value of type 'float'. +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 index 7717c5b7393..1905c5977d0 100644 --- a/tests/fsharp/core/auto-widen/5.0/test.fsx +++ b/tests/fsharp/core/auto-widen/5.0/test.fsx @@ -1,6 +1,9 @@ + #r "System.Xml.Linq.dll" #r "System.Xml.XDocument.dll" +let mutable failures : string list = [] + open System module BasicTypeDirectedConversionsToObj = @@ -45,7 +48,11 @@ module BasicTypeDirectedConversionsForFuncReturn = 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 @@ -157,11 +164,11 @@ module ConvertViaOpImplicit4 = static member M1(C:C) = 1 let x = C.M1(2) -module rec ConvertViaOpImplicit5 = - type Y() = - static member op_Implicit(y:Y) = X() +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 = @@ -181,106 +188,280 @@ module ConvertViaNullable = let x = f 2 let annotations = - let _ : obj = (1,2) - let _ : obj * obj = (1,2) + let v1 : obj = (1,2) + let v2 : obj * obj = (1,2) // structure through let - let _ : (obj * obj) = (let x = 1 in let y = 2 in (x,y)) + let v3 : (obj * obj) = (let x = 1 in let y = 2 in (x,y)) // structure through let rec - let _ : (obj * obj) = (let rec f x = x in (3,4.0)) + let v4 : (obj * obj) = (let rec f x = x in (3,4.0)) // structure through sequence - let _ : (obj * obj) = (); (3,4.0) + let v5 : (obj * obj) = (); (3,4.0) // struct tuple - let _ : struct (obj * obj) = struct (1,2) + let v6 : struct (obj * obj) = struct (1,2) // record (both field and overall result) - // let _ : obj = { F1 = (1, 2) } // TODO + 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 _ : {| A: obj |} = {| A = 1 |} + let v15 : {| A: obj |} = {| A = 1 |} // lambda return - let _ : (unit -> obj) = (fun () -> 1) + let v16 : (unit -> obj) = (fun () -> 1) // function lambda return - let _ : (int -> obj) = (function 1 -> 1 | 2 -> 3.0 | _ -> 4uy) + let v17 : (int -> obj) = (function 1 -> 1 | 2 -> 3.0 | _ -> 4uy) - let _ : (unit -> obj * obj) = (fun () -> (1,2)) + let v18 : (unit -> obj * obj) = (fun () -> (1,2)) // constants (1 :> System.IComparable) |> ignore - let _ : System.IComparable = 1 + let v19 : System.IComparable = 1 // array constants - let _ : System.Array = [| 1us |] + let v20 : System.Array = [| 1us |] - let _ : System.Array = [| 1I |] + let v21 : System.Array = [| 1I |] - let _ : System.IComparable = 1I + let v22 : System.IComparable = 1I // property - let _ : System.IComparable = System.String.Empty + let v23 : System.IComparable = System.String.Empty // method - let _ : System.IComparable = System.String.Format("") + let v24 : System.IComparable = System.String.Format("") - let _ : obj = System.String.Format("") + let v25 : obj = System.String.Format("") - let _ : System.IComparable = System.String.Format("") + let v26 : System.IComparable = System.String.Format("") // array constants - let _ : obj[] = [| 1 |] - let _ : (obj * obj)[] = [| (1,1) |] - let _ : (obj * obj)[] = [| ("abc",1) |] - let _ : (string * obj)[] = [| ("abc",1) |] - let _ : (string * obj)[] = [| ("abc",1); ("abc",3.0) |] - let _ : (string * obj)[] = [| Unchecked.defaultof<_>; ("abc",3.0) |] - let _ : struct (string * obj)[] = [| Unchecked.defaultof<_>; struct ("abc",3.0) |] - - let _ : obj = 1 - let _ : obj = (1 : int) - let _ : obj = "" - let _ : obj = ("" : string) - let _ : obj = ("" : System.IComparable) - let _ : obj = ("" : _) - let _ : obj = ("" : obj) - let _ : obj = { new System.ICloneable with member x.Clone() = obj() } - let _ : obj = "" - let _ : obj = string "" - let _ : obj = id "" + 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 _ : obj = if true then 1 else 3.0 - let _ : obj = (if true then 1 else 3.0) - let _ : obj = (if true then 1 elif true then 2uy else 3.0) + 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 _ : obj = try 1 with _ -> 3.0 + let v48 : obj = try 1 with _ -> 3.0 // try-finally - let _ : obj = try 1 finally () + let v49 : obj = try 1 finally () // match - let _ : obj = match true with true -> 1 | _ -> 3.0 + let v50 : obj = match true with true -> 1 | _ -> 3.0 () let f1 () : obj = 1 let f2 () : obj = if true then 1 else 3.0 -#if NEGATIVE -let annotations = - (id "" : obj) |> ignore /// note, the 'obj' annotation correctly instantiates the type variable to 'obj' - ((if true then ()) : obj) |> ignore - -let f3 x = if true then 1 else 3.0 -#endif +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/test.bsl b/tests/fsharp/core/auto-widen/preview/test.bsl index b17a54f2b9d..89af8192c4c 100644 --- a/tests/fsharp/core/auto-widen/preview/test.bsl +++ b/tests/fsharp/core/auto-widen/preview/test.bsl @@ -95,13 +95,94 @@ test.fsx(186,27,186,28): typecheck error FS3386: This expression uses an implici test.fsx(188,15,188,16): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'Nullable'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(315,7,315,22): typecheck error FS0001: This expression was expected to have type - 'unit' -but here has type - 'obj' +test.fsx(313,37,313,38): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(317,32,317,35): typecheck error FS0193: Type constraint mismatch. The type - 'float' -is not compatible with type - 'int' +test.fsx(314,37,314,38): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(317,50,317,51): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(319,52,319,53): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(320,37,320,38): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(323,57,323,58): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(325,57,325,58): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(326,37,326,38): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(328,42,328,43): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(330,42,330,43): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(331,38,331,39): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(335,36,335,37): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(337,17,337,18): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(341,30,341,31): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(344,32,344,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(346,17,346,18): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(351,37,351,38): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(354,37,354,38): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(356,17,356,18): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(359,21,359,22): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(362,21,362,22): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(364,17,364,18): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(368,39,368,40): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(369,39,369,40): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(372,52,372,53): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(374,54,374,55): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(375,39,375,40): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(378,59,378,60): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(380,59,380,60): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(381,39,381,40): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(383,44,383,45): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(385,44,385,45): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(386,40,386,41): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(390,37,390,38): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(391,39,391,40): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(394,52,394,53): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(396,54,396,55): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(397,39,397,40): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(400,59,400,60): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(402,59,402,60): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(403,39,403,40): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(405,44,405,45): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(407,44,407,45): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(408,40,408,41): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(452,32,452,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(454,46,454,47): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. diff --git a/tests/fsharp/core/auto-widen/preview/test.fsx b/tests/fsharp/core/auto-widen/preview/test.fsx index 331c3ae9d0b..1905c5977d0 100644 --- a/tests/fsharp/core/auto-widen/preview/test.fsx +++ b/tests/fsharp/core/auto-widen/preview/test.fsx @@ -309,13 +309,149 @@ let annotations = let f1 () : obj = 1 let f2 () : obj = if true then 1 else 3.0 -#if NEGATIVE -let annotations = - (id "" : obj) |> ignore /// note, the 'obj' annotation correctly instantiates the type variable to 'obj' - ((if true then ()) : obj) |> ignore - -let f3 x = if true then 1 else 3.0 -#endif +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" diff --git a/tests/fsharp/tests.fs b/tests/fsharp/tests.fs index 64e73650991..8018ebde286 100644 --- a/tests/fsharp/tests.fs +++ b/tests/fsharp/tests.fs @@ -2482,6 +2482,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" diff --git a/tests/fsharp/typecheck/sigs/version50/neg20.bsl b/tests/fsharp/typecheck/sigs/version50/neg20.bsl index 4227ab07193..75d06ce1332 100644 --- a/tests/fsharp/typecheck/sigs/version50/neg20.bsl +++ b/tests/fsharp/typecheck/sigs/version50/neg20.bsl @@ -305,7 +305,7 @@ neg20.fs(195,5,195,10): typecheck error FS0842: This attribute is not valid for neg20.fs(198,5,198,11): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(202,7,202,9): typecheck error FS0825: The 'DefaultValue' attribute may only be used on 'val' declarations +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 diff --git a/tests/service/ServiceUntypedParseTests.fs b/tests/service/ServiceUntypedParseTests.fs index 60981c51bae..c609d8d488a 100644 --- a/tests/service/ServiceUntypedParseTests.fs +++ b/tests/service/ServiceUntypedParseTests.fs @@ -185,7 +185,7 @@ let ``SynType.Paren ranges`` () = let (SynModuleOrNamespace (decls = decls)) = parseSourceCodeAndGetModule source decls |> List.map (fun decl -> match decl with - | SynModuleDecl.DoExpr (expr = SynExpr.Paren (expr = SynExpr.Typed (_, synType, _))) -> + | SynModuleDecl.DoExpr (expr = SynExpr.Paren (expr = SynExpr.Typed (_, synType ,_))) -> getParenTypes synType |> List.map (fun synType -> getRangeCoords synType.Range) | _ -> failwith "Could not get binding") diff --git a/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs b/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs index 4a35de47ee9..af3a35a80fe 100644 --- a/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs +++ b/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs @@ -3927,7 +3927,6 @@ let x = query { for bbbb in abbbbc(*D0*) do [ "Chars" ] // should not contain (documenting the undesirable behavior, that this does not show up) [] - //[] member public this.``BY_DESIGN.ExplicitlyCloseTheParens.Bug73940``() = AssertAutoCompleteContains [ @" From 6de01a69fb26c5eac49c0855aebc3be761ba486c Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 25 May 2021 18:42:45 +0100 Subject: [PATCH 31/42] update baselines --- tests/fsharp/typecheck/sigs/neg24.bsl | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/tests/fsharp/typecheck/sigs/neg24.bsl b/tests/fsharp/typecheck/sigs/neg24.bsl index fcf7a40e45b..ffc702de46b 100644 --- a/tests/fsharp/typecheck/sigs/neg24.bsl +++ b/tests/fsharp/typecheck/sigs/neg24.bsl @@ -17,17 +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 FS0193: Type constraint mismatch. The type - 'int' -is not compatible with type - 'unit' - - -neg24.fs(302,36,302,37): typecheck error FS0193: Type constraint mismatch. The type - 'int' -is not compatible with type - 'unit' +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,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(304,11,305,32): typecheck error FS0193: Type constraint mismatch. The type 'int' @@ -37,11 +29,7 @@ is not compatible with type 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 FS0193: Type constraint mismatch. The type - 'int' -is not compatible with type - 'unit' - +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'. From 85c0117ea7abf5983ce9c1bb37077be46cb360d0 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Wed, 26 May 2021 17:02:22 +0100 Subject: [PATCH 32/42] cache implicit operator lookup --- src/fsharp/CheckDeclarations.fs | 2 +- src/fsharp/CheckExpressions.fs | 2 +- src/fsharp/ConstraintSolver.fs | 2 - src/fsharp/InfoReader.fs | 588 +++++++++++++++++--------------- src/fsharp/InfoReader.fsi | 44 ++- src/fsharp/MethodCalls.fs | 28 +- 6 files changed, 376 insertions(+), 290 deletions(-) diff --git a/src/fsharp/CheckDeclarations.fs b/src/fsharp/CheckDeclarations.fs index 76e40e8b098..954ad466ebd 100644 --- a/src/fsharp/CheckDeclarations.fs +++ b/src/fsharp/CheckDeclarations.fs @@ -1875,7 +1875,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 ca86473154b..8aa2127ccac 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -2941,7 +2941,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 && ( diff --git a/src/fsharp/ConstraintSolver.fs b/src/fsharp/ConstraintSolver.fs index cb8796111d0..440a8957dab 100644 --- a/src/fsharp/ConstraintSolver.fs +++ b/src/fsharp/ConstraintSolver.fs @@ -2798,7 +2798,6 @@ and ResolveOverloading let otherWarnCount = List.length otherWarnings // Prefer methods that don't use type-directed conversion - // Note: Relies on 'compare' respecting true > false let c = compare (match usesTDC1 with TypeDirectedConversionUsed.No -> 1 | _ -> 0) (match usesTDC2 with TypeDirectedConversionUsed.No -> 1 | _ -> 0) if c <> 0 then c else @@ -2903,7 +2902,6 @@ and ResolveOverloading if c <> 0 then c else 0 - let bestMethods = let indexedApplicableMeths = applicableMeths |> List.indexed diff --git a/src/fsharp/InfoReader.fs b/src/fsharp/InfoReader.fs index e04b5fb11a3..272bec10f6e 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,45 @@ 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 + [] + 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 +677,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 +692,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 +735,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 +856,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/MethodCalls.fs b/src/fsharp/MethodCalls.fs index a0e9c63c293..b670fb3f872 100644 --- a/src/fsharp/MethodCalls.fs +++ b/src/fsharp/MethodCalls.fs @@ -163,12 +163,22 @@ let AdjustDelegateTy (infoReader: InfoReader) actualTy reqdTy m = // 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 && not (isTyparTy g actualTy) then + 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 @@ -177,11 +187,20 @@ let TryFindRelevantImplicitConversion (infoReader: InfoReader) ad reqdTy actualT | _ -> 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) then + (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 + let implicits = - TryFindIntrinsicMethInfo infoReader m ad "op_Implicit" reqdTy2 @ - TryFindIntrinsicMethInfo infoReader m ad "op_Implicit" actualTy + infoReader.FindImplicitConversions m ad actualTy @ + infoReader.FindImplicitConversions m ad reqdTy2 + let implicits = implicits |> List.filter (fun minfo -> not minfo.IsInstance && @@ -192,6 +211,7 @@ let TryFindRelevantImplicitConversion (infoReader: InfoReader) ad reqdTy actualT (let rty = minfo.GetFSharpReturnTy(amap, m, []) typeEquiv g rty reqdTy2) ) + match implicits with | [minfo] -> Some (minfo, (reqdTy, reqdTy2, ignore)) From 8bb487c1b213caf5d508b98fa4c8a08988b1da23 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 7 Jun 2021 15:19:43 +0100 Subject: [PATCH 33/42] add op_Implicit tests: checks, options, ambiguities, extrinsic extensions --- src/fsharp/FSharp.Core/prim-types.fsi | 4 + src/fsharp/InfoReader.fs | 3 + src/fsharp/MethodCalls.fs | 101 +- src/fsharp/TypedTreeOps.fs | 5 + src/fsharp/TypedTreeOps.fsi | 3 + src/fsharp/service/ServiceUntypedParse.fs | 1723 ----------------- tests/fsharp/core/auto-widen/preview/test.bsl | 29 + tests/fsharp/core/auto-widen/preview/test.fsx | 85 + tests/fsharp/tests.fs | 2 +- tests/fsharp/typecheck/sigs/neg20.bsl | 10 + tests/fsharp/typecheck/sigs/neg20.fs | 4 + 11 files changed, 195 insertions(+), 1774 deletions(-) delete mode 100755 src/fsharp/service/ServiceUntypedParse.fs diff --git a/src/fsharp/FSharp.Core/prim-types.fsi b/src/fsharp/FSharp.Core/prim-types.fsi index 2ed374eb5ce..5cd6e962696 100644 --- a/src/fsharp/FSharp.Core/prim-types.fsi +++ b/src/fsharp/FSharp.Core/prim-types.fsi @@ -2394,6 +2394,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 @@ -2469,6 +2471,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 272bec10f6e..e3d48724661 100644 --- a/src/fsharp/InfoReader.fs +++ b/src/fsharp/InfoReader.fs @@ -643,6 +643,9 @@ type InfoReader(g: TcGlobals, amap: Import.ImportMap) as this = 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 diff --git a/src/fsharp/MethodCalls.fs b/src/fsharp/MethodCalls.fs index b670fb3f872..acd08624cd2 100644 --- a/src/fsharp/MethodCalls.fs +++ b/src/fsharp/MethodCalls.fs @@ -1094,6 +1094,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 //------------------------------------------------------------------------- @@ -1177,6 +1227,7 @@ let rec AdjustExprForTypeDirectedConversions tcVal (g: TcGlobals) amap infoReade 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 @@ -1926,56 +1977,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/TypedTreeOps.fs b/src/fsharp/TypedTreeOps.fs index 98abfb00672..bff3fc4bb10 100644 --- a/src/fsharp/TypedTreeOps.fs +++ b/src/fsharp/TypedTreeOps.fs @@ -3279,6 +3279,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 8e3dc20b995..ab3fecbf49a 100755 --- a/src/fsharp/TypedTreeOps.fsi +++ b/src/fsharp/TypedTreeOps.fsi @@ -1422,6 +1422,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/service/ServiceUntypedParse.fs b/src/fsharp/service/ServiceUntypedParse.fs deleted file mode 100755 index 1fd389f21e1..00000000000 --- a/src/fsharp/service/ServiceUntypedParse.fs +++ /dev/null @@ -1,1723 +0,0 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. - -//---------------------------------------------------------------------------- -// Open up the compiler as an incremental service for parsing, -// type checking and intellisense-like environment-reporting. -//-------------------------------------------------------------------------- - -namespace FSharp.Compiler.SourceCodeServices - -open System -open System.IO -open System.Collections.Generic -open System.Diagnostics -open System.Text.RegularExpressions - -open FSharp.Compiler -open FSharp.Compiler.AbstractIL.Internal.Library -open FSharp.Compiler.CompilerConfig -open FSharp.Compiler.Lib -open FSharp.Compiler.SourceCodeServices.PrettyNaming -open FSharp.Compiler.SyntaxTree -open FSharp.Compiler.SyntaxTreeOps -open FSharp.Compiler.Text -open FSharp.Compiler.Text.Pos -open FSharp.Compiler.Text.Range - -/// Methods for dealing with F# sources files. -module SourceFile = - - /// Source file extensions - let private compilableExtensions = FSharpSigFileSuffixes @ FSharpImplFileSuffixes @ FSharpScriptFileSuffixes - - /// Single file projects extensions - let private singleFileProjectExtensions = FSharpScriptFileSuffixes - - /// Whether or not this file is compilable - let IsCompilable file = - let ext = Path.GetExtension file - compilableExtensions |> List.exists(fun e->0 = String.Compare(e, ext, StringComparison.OrdinalIgnoreCase)) - - /// Whether or not this file should be a single-file project - let MustBeSingleFileProject file = - let ext = Path.GetExtension file - singleFileProjectExtensions |> List.exists(fun e-> 0 = String.Compare(e, ext, StringComparison.OrdinalIgnoreCase)) - -module SourceFileImpl = - let IsInterfaceFile file = - let ext = Path.GetExtension file - 0 = String.Compare(".fsi", ext, StringComparison.OrdinalIgnoreCase) - - /// Additional #defines that should be in place when editing a file in a file editor such as VS. - let AdditionalDefinesForUseInEditor(isInteractive: bool) = - if isInteractive then ["INTERACTIVE";"EDITING"] // This is still used by the foreground parse - else ["COMPILED";"EDITING"] - -type CompletionPath = string list * string option // plid * residue - -[] -type InheritanceOrigin = - | Class - | Interface - | Unknown - -[] -type InheritanceContext = - | Class - | Interface - | Unknown - -[] -type RecordContext = - | CopyOnUpdate of range: range * path: CompletionPath - | Constructor of typeName: string - | New of path: CompletionPath - -[] -type CompletionContext = - /// Completion context cannot be determined due to errors - | Invalid - - /// Completing something after the inherit keyword - | Inherit of context: InheritanceContext * path: CompletionPath - - /// Completing records field - | RecordField of context: RecordContext - - | RangeOperator - - /// Completing named parameters\setters in parameter list of constructor\method calls - /// end of name ast node * list of properties\parameters that were already set - | ParameterList of pos * HashSet - - | AttributeApplication - - | OpenDeclaration of isOpenType: bool - - /// Completing pattern type (e.g. foo (x: |)) - | PatternType - -//---------------------------------------------------------------------------- -// FSharpParseFileResults -//---------------------------------------------------------------------------- - -[] -type FSharpParseFileResults(errors: FSharpDiagnostic[], input: ParsedInput option, parseHadErrors: bool, dependencyFiles: string[]) = - - member _.Errors = errors - - member _.ParseHadErrors = parseHadErrors - - member _.ParseTree = input - - member scope.TryRangeOfNameOfNearestOuterBindingContainingPos pos = - let tryGetIdentRangeFromBinding binding = - match binding with - | SynBinding.Binding (_, _, _, _, _, _, _, headPat, _, _, _, _) -> - match headPat with - | SynPat.LongIdent (longIdentWithDots, _, _, _, _, _) -> - Some longIdentWithDots.Range - | SynPat.Named(_, ident, false, _, _) -> - Some ident.idRange - | _ -> - None - - let rec walkBinding expr workingRange = - match expr with - - // This lets us dive into subexpressions that may contain the binding we're after - | SynExpr.Sequential (_, _, expr1, expr2, _) -> - if rangeContainsPos expr1.Range pos then - walkBinding expr1 workingRange - else - walkBinding expr2 workingRange - - - | SynExpr.LetOrUse(_, _, bindings, bodyExpr, _) -> - let potentialNestedRange = - bindings - |> List.tryFind (fun binding -> rangeContainsPos binding.RangeOfBindingAndRhs pos) - |> Option.bind tryGetIdentRangeFromBinding - match potentialNestedRange with - | Some range -> - walkBinding bodyExpr range - | None -> - walkBinding bodyExpr workingRange - - - | _ -> - Some workingRange - - match scope.ParseTree with - | Some input -> - AstTraversal.Traverse(pos, input, { new AstTraversal.AstVisitorBase<_>() with - member _.VisitExpr(_, _, defaultTraverse, expr) = - defaultTraverse expr - - override _.VisitBinding(defaultTraverse, binding) = - match binding with - | SynBinding.Binding (_, _, _, _, _, _, _, _, _, expr, _range, _) as b when rangeContainsPos b.RangeOfBindingAndRhs pos -> - match tryGetIdentRangeFromBinding b with - | Some range -> walkBinding expr range - | None -> None - | _ -> defaultTraverse binding }) - | None -> None - - member scope.TryIdentOfPipelineContainingPosAndNumArgsApplied pos = - match scope.ParseTree with - | Some input -> - AstTraversal.Traverse(pos, input, { new AstTraversal.AstVisitorBase<_>() with - member _.VisitExpr(_, _, defaultTraverse, expr) = - match expr with - | SynExpr.App (_, _, SynExpr.App(_, true, SynExpr.Ident ident, _, _), argExpr, _) when rangeContainsPos argExpr.Range pos -> - match argExpr with - | SynExpr.App(_, _, _, SynExpr.Paren(expr, _, _, _), _) when rangeContainsPos expr.Range pos -> - None - | _ -> - if ident.idText = "op_PipeRight" then - Some (ident, 1) - elif ident.idText = "op_PipeRight2" then - Some (ident, 2) - elif ident.idText = "op_PipeRight3" then - Some (ident, 3) - else - None - | _ -> defaultTraverse expr - }) - | None -> None - - member scope.IsPosContainedInApplication pos = - match scope.ParseTree with - | Some input -> - let result = - AstTraversal.Traverse(pos, input, { new AstTraversal.AstVisitorBase<_>() with - member _.VisitExpr(_, traverseSynExpr, defaultTraverse, expr) = - match expr with - | SynExpr.App(_, _, _, SynExpr.CompExpr (_, _, expr, _), range) when rangeContainsPos range pos -> - traverseSynExpr expr - | SynExpr.App (_, _, _, _, range) when rangeContainsPos range pos -> - Some range - | _ -> defaultTraverse expr - }) - result.IsSome - | None -> false - - member scope.TryRangeOfFunctionOrMethodBeingApplied pos = - let rec getIdentRangeForFuncExprInApp traverseSynExpr expr pos = - match expr with - | SynExpr.Ident ident -> Some ident.idRange - - | SynExpr.LongIdent (_, _, _, range) -> Some range - - | SynExpr.Paren (expr, _, _, range) when rangeContainsPos range pos -> - getIdentRangeForFuncExprInApp traverseSynExpr expr pos - - | SynExpr.App (_, _, funcExpr, argExpr, _) -> - match argExpr with - | SynExpr.App (_, _, _, _, range) when rangeContainsPos range pos -> - getIdentRangeForFuncExprInApp traverseSynExpr argExpr pos - - // Special case: `async { ... }` is actually a CompExpr inside of the argExpr of a SynExpr.App - | SynExpr.CompExpr (_, _, expr, range) when rangeContainsPos range pos -> - getIdentRangeForFuncExprInApp traverseSynExpr expr pos - - | SynExpr.Paren (expr, _, _, range) when rangeContainsPos range pos -> - getIdentRangeForFuncExprInApp traverseSynExpr expr pos - - | _ -> - match funcExpr with - | SynExpr.App (_, true, _, _, _) when rangeContainsPos argExpr.Range pos -> - // x |> List.map - // Don't dive into the funcExpr (the operator expr) - // because we dont want to offer sig help for that! - getIdentRangeForFuncExprInApp traverseSynExpr argExpr pos - | _ -> - // Generally, we want to dive into the func expr to get the range - // of the identifier of the function we're after - getIdentRangeForFuncExprInApp traverseSynExpr funcExpr pos - - | SynExpr.LetOrUse (_, _, bindings, body, range) when rangeContainsPos range pos -> - let binding = - bindings - |> List.tryFind (fun x -> rangeContainsPos x.RangeOfBindingAndRhs pos) - match binding with - | Some(SynBinding.Binding(_, _, _, _, _, _, _, _, _, expr, _, _)) -> - getIdentRangeForFuncExprInApp traverseSynExpr expr pos - | None -> - getIdentRangeForFuncExprInApp traverseSynExpr body pos - - | SynExpr.IfThenElse (ifExpr, thenExpr, elseExpr, _, _, _, range) when rangeContainsPos range pos -> - if rangeContainsPos ifExpr.Range pos then - getIdentRangeForFuncExprInApp traverseSynExpr ifExpr pos - elif rangeContainsPos thenExpr.Range pos then - getIdentRangeForFuncExprInApp traverseSynExpr thenExpr pos - else - match elseExpr with - | None -> None - | Some expr -> - getIdentRangeForFuncExprInApp traverseSynExpr expr pos - - | SynExpr.Match (_, expr, clauses, range) when rangeContainsPos range pos -> - if rangeContainsPos expr.Range pos then - getIdentRangeForFuncExprInApp traverseSynExpr expr pos - else - let clause = clauses |> List.tryFind (fun clause -> rangeContainsPos clause.Range pos) - match clause with - | None -> None - | Some clause -> - match clause with - | SynMatchClause.Clause (_, whenExpr, resultExpr, _, _) -> - match whenExpr with - | None -> - getIdentRangeForFuncExprInApp traverseSynExpr resultExpr pos - | Some whenExpr -> - if rangeContainsPos whenExpr.Range pos then - getIdentRangeForFuncExprInApp traverseSynExpr whenExpr pos - else - getIdentRangeForFuncExprInApp traverseSynExpr resultExpr pos - - - // Ex: C.M(x, y, ...) <--- We want to find where in the tupled application the call is being made - | SynExpr.Tuple(_, exprs, _, tupRange) when rangeContainsPos tupRange pos -> - let expr = exprs |> List.tryFind (fun expr -> rangeContainsPos expr.Range pos) - match expr with - | None -> None - | Some expr -> - getIdentRangeForFuncExprInApp traverseSynExpr expr pos - - // Capture the body of a lambda, often nested in a call to a collection function - | SynExpr.Lambda(_, _, _args, body, _, _) when rangeContainsPos body.Range pos -> - getIdentRangeForFuncExprInApp traverseSynExpr body pos - - | SynExpr.Do(expr, range) when rangeContainsPos range pos -> - getIdentRangeForFuncExprInApp traverseSynExpr expr pos - - | SynExpr.Assert(expr, range) when rangeContainsPos range pos -> - getIdentRangeForFuncExprInApp traverseSynExpr expr pos - - | SynExpr.ArbitraryAfterError (_debugStr, range) when rangeContainsPos range pos -> - Some range - - | expr -> - traverseSynExpr expr - |> Option.map (fun expr -> expr) - - match scope.ParseTree with - | Some input -> - AstTraversal.Traverse(pos, input, { new AstTraversal.AstVisitorBase<_>() with - member _.VisitExpr(_, traverseSynExpr, defaultTraverse, expr) = - match expr with - | SynExpr.App (_, _, _funcExpr, _, range) as app when rangeContainsPos range pos -> - getIdentRangeForFuncExprInApp traverseSynExpr app pos - | _ -> defaultTraverse expr - }) - | None -> None - - member scope.GetAllArgumentsForFunctionApplicationAtPostion pos = - match input with - | Some input -> SynExprAppLocationsImpl.getAllCurriedArgsAtPosition pos input - | None -> None - - member scope.TryRangeOfParenEnclosingOpEqualsGreaterUsage opGreaterEqualPos = - let (|Ident|_|) ofName = - function | SynExpr.Ident ident when ident.idText = ofName -> Some () - | _ -> None - let (|InfixAppOfOpEqualsGreater|_|) = - function | SynExpr.App(ExprAtomicFlag.NonAtomic, false, SynExpr.App(ExprAtomicFlag.NonAtomic, true, Ident "op_EqualsGreater", actualParamListExpr, _), actualLambdaBodyExpr, _) -> - Some (actualParamListExpr, actualLambdaBodyExpr) - | _ -> None - - match scope.ParseTree with - | Some parseTree -> - AstTraversal.Traverse(opGreaterEqualPos, parseTree, { new AstTraversal.AstVisitorBase<_>() with - member _.VisitExpr(_, _, defaultTraverse, expr) = - match expr with - | SynExpr.Paren((InfixAppOfOpEqualsGreater(lambdaArgs, lambdaBody) as app), _, _, _) -> - Some (app.Range, lambdaArgs.Range, lambdaBody.Range) - | _ -> defaultTraverse expr - member _.VisitBinding(defaultTraverse, binding) = - match binding with - | SynBinding.Binding (_, SynBindingKind.NormalBinding, _, _, _, _, _, _, _, (InfixAppOfOpEqualsGreater(lambdaArgs, lambdaBody) as app), _, _) -> - Some(app.Range, lambdaArgs.Range, lambdaBody.Range) - | _ -> defaultTraverse binding }) - | None -> None - - member scope.TryRangeOfExprInYieldOrReturn pos = - match scope.ParseTree with - | Some parseTree -> - AstTraversal.Traverse(pos, parseTree, { new AstTraversal.AstVisitorBase<_>() with - member _.VisitExpr(_path, _, defaultTraverse, expr) = - match expr with - | SynExpr.YieldOrReturn(_, expr, range) - | SynExpr.YieldOrReturnFrom(_, expr, range) when rangeContainsPos range pos -> - Some expr.Range - | _ -> defaultTraverse expr }) - | None -> None - - member scope.TryRangeOfRecordExpressionContainingPos pos = - match input with - | Some input -> - AstTraversal.Traverse(pos, input, { new AstTraversal.AstVisitorBase<_>() with - member _.VisitExpr(_, _, defaultTraverse, expr) = - match expr with - | SynExpr.Record(_, _, _, range) when rangeContainsPos range pos -> - Some range - | _ -> defaultTraverse expr }) - | None -> - None - - member _.TryRangeOfRefCellDereferenceContainingPos expressionPos = - match input with - | Some input -> - AstTraversal.Traverse(expressionPos, input, { new AstTraversal.AstVisitorBase<_>() with - member _.VisitExpr(_, _, defaultTraverse, expr) = - match expr with - | SynExpr.App(_, false, SynExpr.Ident funcIdent, expr, _) -> - if funcIdent.idText = "op_Dereference" && rangeContainsPos expr.Range expressionPos then - Some funcIdent.idRange - else - None - | _ -> defaultTraverse expr }) - | None -> - None - - member _.FindNoteworthyParamInfoLocations pos = - match input with - | Some input -> FSharpNoteworthyParamInfoLocations.Find(pos, input) - | _ -> None - - member _.IsPositionContainedInACurriedParameter pos = - match input with - | Some input -> - let result = - AstTraversal.Traverse(pos, input, { new AstTraversal.AstVisitorBase<_>() with - member _.VisitExpr(_path, traverseSynExpr, defaultTraverse, expr) = - defaultTraverse(expr) - - override _.VisitBinding (_, binding) = - match binding with - | Binding(_, _, _, _, _, _, valData, _, _, _, range, _) when rangeContainsPos range pos -> - let info = valData.SynValInfo.CurriedArgInfos - let mutable found = false - for group in info do - for arg in group do - match arg.Ident with - | Some ident when rangeContainsPos ident.idRange pos -> - found <- true - | _ -> () - if found then Some range else None - | _ -> - None - }) - result.IsSome - | _ -> false - - /// Get declared items and the selected item at the specified location - member _.GetNavigationItemsImpl() = - ErrorScope.Protect range0 - (fun () -> - match input with - | Some (ParsedInput.ImplFile _ as p) -> - FSharpNavigation.getNavigation p - | Some (ParsedInput.SigFile _) -> - FSharpNavigation.empty - | _ -> - FSharpNavigation.empty) - (fun err -> - Trace.TraceInformation(sprintf "FCS: recovering from error in GetNavigationItemsImpl: '%s'" err) - FSharpNavigation.empty) - - member _.ValidateBreakpointLocationImpl pos = - let isMatchRange m = rangeContainsPos m pos || m.StartLine = pos.Line - - // Process let-binding - let findBreakPoints () = - let checkRange m = [ if isMatchRange m then yield m ] - let walkBindSeqPt sp = [ match sp with DebugPointAtBinding m -> yield! checkRange m | _ -> () ] - let walkForSeqPt sp = [ match sp with DebugPointAtFor.Yes m -> yield! checkRange m | _ -> () ] - let walkWhileSeqPt sp = [ match sp with DebugPointAtWhile.Yes m -> yield! checkRange m | _ -> () ] - let walkTrySeqPt sp = [ match sp with DebugPointAtTry.Yes m -> yield! checkRange m | _ -> () ] - let walkWithSeqPt sp = [ match sp with DebugPointAtWith.Yes m -> yield! checkRange m | _ -> () ] - let walkFinallySeqPt sp = [ match sp with DebugPointAtFinally.Yes m -> yield! checkRange m | _ -> () ] - - let rec walkBind (Binding(_, _, _, _, _, _, SynValData(memFlagsOpt, _, _), synPat, _, synExpr, _, spInfo)) = - [ // Don't yield the binding sequence point if there are any arguments, i.e. we're defining a function or a method - let isFunction = - Option.isSome memFlagsOpt || - match synPat with - | SynPat.LongIdent (_, _, _, SynArgPats.Pats args, _, _) when not (List.isEmpty args) -> true - | _ -> false - if not isFunction then - yield! walkBindSeqPt spInfo - - yield! walkExpr (isFunction || (match spInfo with DebugPointAtBinding _ -> false | _-> true)) synExpr ] - - and walkExprs es = List.collect (walkExpr false) es - and walkBinds es = List.collect walkBind es - and walkMatchClauses cl = - [ for (Clause(_, whenExpr, e, _, _)) in cl do - match whenExpr with - | Some e -> yield! walkExpr false e - | _ -> () - yield! walkExpr true e ] - - and walkExprOpt (spAlways: bool) eOpt = [ match eOpt with Some e -> yield! walkExpr spAlways e | _ -> () ] - - and IsBreakableExpression e = - match e with - | SynExpr.Match _ - | SynExpr.IfThenElse _ - | SynExpr.For _ - | SynExpr.ForEach _ - | SynExpr.While _ -> true - | _ -> not (IsControlFlowExpression e) - - // Determine the breakpoint locations for an expression. spAlways indicates we always - // emit a breakpoint location for the expression unless it is a syntactic control flow construct - and walkExpr (spAlways: bool) e = - let m = e.Range - if not (isMatchRange m) then [] else - [ if spAlways && IsBreakableExpression e then - yield! checkRange m - - match e with - | SynExpr.ArbitraryAfterError _ - | SynExpr.LongIdent _ - | SynExpr.LibraryOnlyILAssembly _ - | SynExpr.LibraryOnlyStaticOptimization _ - | SynExpr.Null _ - | SynExpr.Ident _ - | SynExpr.ImplicitZero _ - | SynExpr.Const _ -> - () - - | SynExpr.Quote (_, _, e, _, _) - | SynExpr.TypeTest (e, _, _) - | SynExpr.Upcast (e, _, _) - | SynExpr.AddressOf (_, e, _, _) - | SynExpr.CompExpr (_, _, e, _) - | SynExpr.ArrayOrListOfSeqExpr (_, e, _) - | SynExpr.Typed (e, _, _, _) - | SynExpr.FromParseError (e, _) - | SynExpr.DiscardAfterMissingQualificationAfterDot (e, _) - | SynExpr.Do (e, _) - | SynExpr.Assert (e, _) - | SynExpr.Fixed (e, _) - | SynExpr.DotGet (e, _, _, _) - | SynExpr.LongIdentSet (_, e, _) - | SynExpr.New (_, _, e, _) - | SynExpr.TypeApp (e, _, _, _, _, _, _) - | SynExpr.LibraryOnlyUnionCaseFieldGet (e, _, _, _) - | SynExpr.Downcast (e, _, _) - | SynExpr.InferredUpcast (e, _) - | SynExpr.InferredDowncast (e, _) - | SynExpr.Lazy (e, _) - | SynExpr.TraitCall (_, _, e, _) - | SynExpr.Paren (e, _, _, _) -> - yield! walkExpr false e - - | SynExpr.InterpolatedString (parts, _, _) -> - yield! walkExprs [ for part in parts do - match part with - | SynInterpolatedStringPart.String _ -> () - | SynInterpolatedStringPart.FillExpr (fillExpr, _) -> yield fillExpr ] - - | SynExpr.YieldOrReturn (_, e, _) - | SynExpr.YieldOrReturnFrom (_, e, _) - | SynExpr.DoBang (e, _) -> - yield! checkRange e.Range - yield! walkExpr false e - - | SynExpr.NamedIndexedPropertySet (_, e1, e2, _) - | SynExpr.DotSet (e1, _, e2, _) - | SynExpr.Set (e1, e2, _) - | SynExpr.LibraryOnlyUnionCaseFieldSet (e1, _, _, e2, _) - | SynExpr.App (_, _, e1, e2, _) -> - yield! walkExpr false e1 - yield! walkExpr false e2 - - | SynExpr.ArrayOrList (_, es, _) - | SynExpr.Tuple (_, es, _, _) -> - yield! walkExprs es - - | SynExpr.Record (_, copyExprOpt, fs, _) -> - match copyExprOpt with - | Some (e, _) -> yield! walkExpr true e - | None -> () - yield! walkExprs (fs |> List.choose p23) - - | SynExpr.AnonRecd (_isStruct, copyExprOpt, fs, _) -> - match copyExprOpt with - | Some (e, _) -> yield! walkExpr true e - | None -> () - yield! walkExprs (fs |> List.map snd) - - | SynExpr.ObjExpr (_, args, bs, is, _, _) -> - match args with - | None -> () - | Some (arg, _) -> yield! walkExpr false arg - yield! walkBinds bs - for (InterfaceImpl(_, bs, _)) in is do yield! walkBinds bs - - | SynExpr.While (spWhile, e1, e2, _) -> - yield! walkWhileSeqPt spWhile - yield! walkExpr false e1 - yield! walkExpr true e2 - - | SynExpr.JoinIn (e1, _range, e2, _range2) -> - yield! walkExpr false e1 - yield! walkExpr false e2 - - | SynExpr.For (spFor, _, e1, _, e2, e3, _) -> - yield! walkForSeqPt spFor - yield! walkExpr false e1 - yield! walkExpr true e2 - yield! walkExpr true e3 - - | SynExpr.ForEach (spFor, _, _, _, e1, e2, _) -> - yield! walkForSeqPt spFor - yield! walkExpr false e1 - yield! walkExpr true e2 - - | SynExpr.MatchLambda (_isExnMatch, _argm, cl, spBind, _wholem) -> - yield! walkBindSeqPt spBind - for (Clause(_, whenExpr, e, _, _)) in cl do - yield! walkExprOpt false whenExpr - yield! walkExpr true e - - | SynExpr.Lambda (_, _, _, e, _, _) -> - yield! walkExpr true e - - | SynExpr.Match (spBind, e, cl, _) -> - yield! walkBindSeqPt spBind - yield! walkExpr false e - for (Clause(_, whenExpr, e, _, _)) in cl do - yield! walkExprOpt false whenExpr - yield! walkExpr true e - - | SynExpr.LetOrUse (_, _, bs, e, _) -> - yield! walkBinds bs - yield! walkExpr true e - - | SynExpr.TryWith (e, _, cl, _, _, spTry, spWith) -> - yield! walkTrySeqPt spTry - yield! walkWithSeqPt spWith - yield! walkExpr true e - yield! walkMatchClauses cl - - | SynExpr.TryFinally (e1, e2, _, spTry, spFinally) -> - yield! walkExpr true e1 - yield! walkExpr true e2 - yield! walkTrySeqPt spTry - yield! walkFinallySeqPt spFinally - - | SynExpr.SequentialOrImplicitYield (spSeq, e1, e2, _, _) - | SynExpr.Sequential (spSeq, _, e1, e2, _) -> - yield! walkExpr (match spSeq with DebugPointAtSequential.ExprOnly -> false | _ -> true) e1 - yield! walkExpr (match spSeq with DebugPointAtSequential.StmtOnly -> false | _ -> true) e2 - - | SynExpr.IfThenElse (e1, e2, e3opt, spBind, _, _, _) -> - yield! walkBindSeqPt spBind - yield! walkExpr false e1 - yield! walkExpr true e2 - yield! walkExprOpt true e3opt - - | SynExpr.DotIndexedGet (e1, es, _, _) -> - yield! walkExpr false e1 - yield! walkExprs [ for e in es do yield! e.Exprs ] - - | SynExpr.DotIndexedSet (e1, es, e2, _, _, _) -> - yield! walkExpr false e1 - yield! walkExprs [ for e in es do yield! e.Exprs ] - yield! walkExpr false e2 - - | SynExpr.DotNamedIndexedPropertySet (e1, _, e2, e3, _) -> - yield! walkExpr false e1 - yield! walkExpr false e2 - yield! walkExpr false e3 - - | SynExpr.LetOrUseBang (spBind, _, _, _, e1, es, e2, _) -> - yield! walkBindSeqPt spBind - yield! walkExpr true e1 - for (andBangSpBind,_,_,_,eAndBang,_) in es do - yield! walkBindSeqPt andBangSpBind - yield! walkExpr true eAndBang - yield! walkExpr true e2 - - | SynExpr.MatchBang (spBind, e, cl, _) -> - yield! walkBindSeqPt spBind - yield! walkExpr false e - for (Clause(_, whenExpr, e, _, _)) in cl do - yield! walkExprOpt false whenExpr - yield! walkExpr true e ] - - // Process a class declaration or F# type declaration - let rec walkTycon (TypeDefn(ComponentInfo(_, _, _, _, _, _, _, _), repr, membDefns, _, m)) = - if not (isMatchRange m) then [] else - [ for memb in membDefns do yield! walkMember memb - match repr with - | SynTypeDefnRepr.ObjectModel(_, membDefns, _) -> - for memb in membDefns do yield! walkMember memb - | _ -> () ] - - // Returns class-members for the right dropdown - and walkMember memb = - if not (rangeContainsPos memb.Range pos) then [] else - [ match memb with - | SynMemberDefn.LetBindings(binds, _, _, _) -> yield! walkBinds binds - | SynMemberDefn.AutoProperty(_attribs, _isStatic, _id, _tyOpt, _propKind, _, _xmlDoc, _access, synExpr, _, _) -> yield! walkExpr true synExpr - | SynMemberDefn.ImplicitCtor(_, _, _, _, _, m) -> yield! checkRange m - | SynMemberDefn.Member(bind, _) -> yield! walkBind bind - | SynMemberDefn.Interface(_, Some membs, _) -> for m in membs do yield! walkMember m - | SynMemberDefn.Inherit(_, _, m) -> - // can break on the "inherit" clause - yield! checkRange m - | SynMemberDefn.ImplicitInherit(_, arg, _, m) -> - // can break on the "inherit" clause - yield! checkRange m - yield! walkExpr true arg - | _ -> () ] - - // Process declarations nested in a module that should be displayed in the left dropdown - // (such as type declarations, nested modules etc.) - let rec walkDecl decl = - [ match decl with - | SynModuleDecl.Let(_, binds, m) when isMatchRange m -> - yield! walkBinds binds - | SynModuleDecl.DoExpr(spExpr, expr, m) when isMatchRange m -> - yield! walkBindSeqPt spExpr - yield! walkExpr false expr - | SynModuleDecl.ModuleAbbrev _ -> () - | SynModuleDecl.NestedModule(_, _isRec, decls, _, m) when isMatchRange m -> - for d in decls do yield! walkDecl d - | SynModuleDecl.Types(tydefs, m) when isMatchRange m -> - for d in tydefs do yield! walkTycon d - | SynModuleDecl.Exception(SynExceptionDefn(SynExceptionDefnRepr(_, _, _, _, _, _), membDefns, _), m) - when isMatchRange m -> - for m in membDefns do yield! walkMember m - | _ -> () ] - - // Collect all the items in a module - let walkModule (SynModuleOrNamespace(_, _, _, decls, _, _, _, m)) = - if isMatchRange m then - List.collect walkDecl decls - else - [] - - /// Get information for implementation file - let walkImplFile (modules: SynModuleOrNamespace list) = List.collect walkModule modules - - match input with - | Some (ParsedInput.ImplFile (ParsedImplFileInput (modules = modules))) -> walkImplFile modules - | _ -> [] - - ErrorScope.Protect range0 - (fun () -> - let locations = findBreakPoints() - - if pos.Column = 0 then - // we have a breakpoint that was set with mouse at line start - match locations |> List.filter (fun m -> m.StartLine = m.EndLine && pos.Line = m.StartLine) with - | [] -> - match locations |> List.filter (fun m -> rangeContainsPos m pos) with - | [] -> - match locations |> List.filter (fun m -> rangeBeforePos m pos |> not) with - | [] -> Seq.tryHead locations - | locationsAfterPos -> Seq.tryHead locationsAfterPos - | coveringLocations -> Seq.tryLast coveringLocations - | locationsOnSameLine -> Seq.tryHead locationsOnSameLine - else - match locations |> List.filter (fun m -> rangeContainsPos m pos) with - | [] -> - match locations |> List.filter (fun m -> rangeBeforePos m pos |> not) with - | [] -> Seq.tryHead locations - | locationsAfterPos -> Seq.tryHead locationsAfterPos - | coveringLocations -> Seq.tryLast coveringLocations) - (fun msg -> - Trace.TraceInformation(sprintf "FCS: recovering from error in ValidateBreakpointLocationImpl: '%s'" msg) - None) - - /// When these files appear or disappear the configuration for the current project is invalidated. - member _.DependencyFiles = dependencyFiles - - member _.FileName = - match input with - | Some (ParsedInput.ImplFile (ParsedImplFileInput (fileName = modname))) - | Some (ParsedInput.SigFile (ParsedSigFileInput (fileName = modname))) -> modname - | _ -> "" - - // Get items for the navigation drop down bar - member scope.GetNavigationItems() = - // This does not need to be run on the background thread - scope.GetNavigationItemsImpl() - - member scope.ValidateBreakpointLocation pos = - // This does not need to be run on the background thread - scope.ValidateBreakpointLocationImpl pos - -type ModuleKind = { IsAutoOpen: bool; HasModuleSuffix: bool } - -[] -type EntityKind = - | Attribute - | Type - | FunctionOrValue of isActivePattern: bool - | Module of ModuleKind - override x.ToString() = sprintf "%A" x - -module UntypedParseImpl = - - let emptyStringSet = HashSet() - - let GetRangeOfExprLeftOfDot(pos: pos, parseTreeOpt) = - match parseTreeOpt with - | None -> None - | Some parseTree -> - let CheckLongIdent(longIdent: LongIdent) = - // find the longest prefix before the "pos" dot - let mutable r = (List.head longIdent).idRange - let mutable couldBeBeforeFront = true - for i in longIdent do - if posGeq pos i.idRange.End then - r <- unionRanges r i.idRange - couldBeBeforeFront <- false - couldBeBeforeFront, r - - AstTraversal.Traverse(pos, parseTree, { new AstTraversal.AstVisitorBase<_>() with - member _.VisitExpr(_path, traverseSynExpr, defaultTraverse, expr) = - let expr = expr // fix debugger locals - match expr with - | SynExpr.LongIdent (_, LongIdentWithDots(longIdent, _), _altNameRefCell, _range) -> - let _, r = CheckLongIdent longIdent - Some r - | SynExpr.LongIdentSet (LongIdentWithDots(longIdent, _), synExpr, _range) -> - if AstTraversal.rangeContainsPosLeftEdgeInclusive synExpr.Range pos then - traverseSynExpr synExpr - else - let _, r = CheckLongIdent longIdent - Some r - | SynExpr.DotGet (synExpr, _dotm, LongIdentWithDots(longIdent, _), _range) -> - if AstTraversal.rangeContainsPosLeftEdgeInclusive synExpr.Range pos then - traverseSynExpr synExpr - else - let inFront, r = CheckLongIdent longIdent - if inFront then - Some (synExpr.Range) - else - // see comment below for SynExpr.DotSet - Some ((unionRanges synExpr.Range r)) - | SynExpr.Set (synExpr, synExpr2, range) -> - if AstTraversal.rangeContainsPosLeftEdgeInclusive synExpr.Range pos then - traverseSynExpr synExpr - elif AstTraversal.rangeContainsPosLeftEdgeInclusive synExpr2.Range pos then - traverseSynExpr synExpr2 - else - Some range - | SynExpr.DotSet (synExpr, LongIdentWithDots(longIdent, _), synExpr2, _range) -> - if AstTraversal.rangeContainsPosLeftEdgeInclusive synExpr.Range pos then - traverseSynExpr synExpr - elif AstTraversal.rangeContainsPosLeftEdgeInclusive synExpr2.Range pos then - traverseSynExpr synExpr2 - else - let inFront, r = CheckLongIdent longIdent - if inFront then - Some (synExpr.Range) - else - // f(0).X.Y.Z - // ^ - // - r has this value - // ---- synExpr.Range has this value - // ------ we want this value - Some ((unionRanges synExpr.Range r)) - | SynExpr.DotNamedIndexedPropertySet (synExpr, LongIdentWithDots(longIdent, _), synExpr2, synExpr3, _range) -> - if AstTraversal.rangeContainsPosLeftEdgeInclusive synExpr.Range pos then - traverseSynExpr synExpr - elif AstTraversal.rangeContainsPosLeftEdgeInclusive synExpr2.Range pos then - traverseSynExpr synExpr2 - elif AstTraversal.rangeContainsPosLeftEdgeInclusive synExpr3.Range pos then - traverseSynExpr synExpr3 - else - let inFront, r = CheckLongIdent longIdent - if inFront then - Some (synExpr.Range) - else - Some ((unionRanges synExpr.Range r)) - | SynExpr.DiscardAfterMissingQualificationAfterDot (synExpr, _range) -> // get this for e.g. "bar()." - if AstTraversal.rangeContainsPosLeftEdgeInclusive synExpr.Range pos then - traverseSynExpr synExpr - else - Some (synExpr.Range) - | SynExpr.FromParseError (synExpr, range) -> - if AstTraversal.rangeContainsPosLeftEdgeInclusive synExpr.Range pos then - traverseSynExpr synExpr - else - Some range - | SynExpr.App (ExprAtomicFlag.NonAtomic, true, (SynExpr.Ident ident), rhs, _) - when ident.idText = "op_ArrayLookup" - && not(AstTraversal.rangeContainsPosLeftEdgeInclusive rhs.Range pos) -> - match defaultTraverse expr with - | None -> - // (expr).(expr) is an ML-deprecated array lookup, but we want intellisense on the dot - // also want it for e.g. [|arr|].(0) - Some (expr.Range) - | x -> x // we found the answer deeper somewhere in the lhs - | SynExpr.Const (SynConst.Double(_), range) -> Some range - | _ -> defaultTraverse expr - }) - - /// searches for the expression island suitable for the evaluation by the debugger - let TryFindExpressionIslandInPosition(pos: pos, parseTreeOpt) = - match parseTreeOpt with - | None -> None - | Some parseTree -> - let getLidParts (lid : LongIdent) = - lid - |> Seq.takeWhile (fun i -> posGeq pos i.idRange.Start) - |> Seq.map (fun i -> i.idText) - |> Seq.toList - - // tries to locate simple expression island - // foundCandidate = false means that we are looking for the candidate expression - // foundCandidate = true - we found candidate (DotGet) and now drill down to the left part - let rec TryGetExpression foundCandidate expr = - match expr with - | SynExpr.Paren (e, _, _, _) when foundCandidate -> - TryGetExpression foundCandidate e - | SynExpr.LongIdent (_isOptional, LongIdentWithDots(lid, _), _altNameRefCell, _m) -> - getLidParts lid |> Some - | SynExpr.DotGet (leftPart, _, LongIdentWithDots(lid, _), _) when (rangeContainsPos (rangeOfLid lid) pos) || foundCandidate -> - // requested position is at the lid part of the DotGet - // process left part and append result to the result of processing lid - let leftPartResult = TryGetExpression true leftPart - match leftPartResult with - | Some leftPartResult -> - [ - yield! leftPartResult - yield! getLidParts lid - ] |> Some - | None -> None - | SynExpr.FromParseError (synExpr, _range) -> TryGetExpression foundCandidate synExpr - | _ -> None - - let rec walker = - { new AstTraversal.AstVisitorBase<_>() with - member this.VisitExpr(_path, traverseSynExpr, defaultTraverse, expr) = - if rangeContainsPos expr.Range pos then - match TryGetExpression false expr with - | (Some parts) -> parts |> String.concat "." |> Some - | _ -> defaultTraverse expr - else - None } - AstTraversal.Traverse(pos, parseTree, walker) - - // Given a cursor position here: - // f(x) . ident - // ^ - // walk the AST to find the position here: - // f(x) . ident - // ^ - // On success, return Some (thatPos, boolTrueIfCursorIsAfterTheDotButBeforeTheIdentifier) - // If there's no dot, return None, so for example - // foo - // ^ - // would return None - // TODO would be great to unify this with GetRangeOfExprLeftOfDot above, if possible, as they are similar - let TryFindExpressionASTLeftOfDotLeftOfCursor(pos, parseTreeOpt) = - match parseTreeOpt with - | None -> None - | Some parseTree -> - let dive x = AstTraversal.dive x - let pick x = AstTraversal.pick pos x - let walker = - { new AstTraversal.AstVisitorBase<_>() with - member this.VisitExpr(_path, traverseSynExpr, defaultTraverse, expr) = - let pick = pick expr.Range - let traverseSynExpr, defaultTraverse, expr = traverseSynExpr, defaultTraverse, expr // for debugging: debugger does not get object expression params as local vars - if not(rangeContainsPos expr.Range pos) then - match expr with - | SynExpr.DiscardAfterMissingQualificationAfterDot (e, _m) -> - // This happens with e.g. "f(x) . $" when you bring up a completion list a few spaces after a dot. The cursor is not 'in the parse tree', - // but the dive algorithm will dive down into this node, and this is the one case where we do want to give a result despite the cursor - // not properly being in a node. - match traverseSynExpr e with - | None -> Some (e.Range.End, false) - | r -> r - | _ -> - // This happens for e.g. "System.Console.[]$", where the ".[]" token is thrown away by the parser and we dive into the System.Console longId - // even though the cursor/dot is not in there. In those cases we want to return None, because there is not really a dot completion before - // the cursor location. - None - else - let rec traverseLidOrElse (optExprIfLeftOfLongId : SynExpr option) (LongIdentWithDots(lid, dots) as lidwd) = - let resultIfLeftOfLongId = - match optExprIfLeftOfLongId with - | None -> None - | Some e -> Some (e.Range.End, posGeq lidwd.Range.Start pos) - match dots |> List.mapi (fun i x -> i, x) |> List.rev |> List.tryFind (fun (_, m) -> posGt pos m.Start) with - | None -> resultIfLeftOfLongId - | Some (n, _) -> Some ((List.item n lid).idRange.End, (List.length lid = n+1) // foo.$ - || (posGeq (List.item (n+1) lid).idRange.Start pos)) // foo.$bar - match expr with - | SynExpr.LongIdent (_isOptional, lidwd, _altNameRefCell, _m) -> - traverseLidOrElse None lidwd - | SynExpr.LongIdentSet (lidwd, exprRhs, _m) -> - [ dive lidwd lidwd.Range (traverseLidOrElse None) - dive exprRhs exprRhs.Range traverseSynExpr - ] |> pick expr - | SynExpr.DotGet (exprLeft, dotm, lidwd, _m) -> - let afterDotBeforeLid = mkRange dotm.FileName dotm.End lidwd.Range.Start - [ dive exprLeft exprLeft.Range traverseSynExpr - dive exprLeft afterDotBeforeLid (fun e -> Some (e.Range.End, true)) - dive lidwd lidwd.Range (traverseLidOrElse (Some exprLeft)) - ] |> pick expr - | SynExpr.DotSet (exprLeft, lidwd, exprRhs, _m) -> - [ dive exprLeft exprLeft.Range traverseSynExpr - dive lidwd lidwd.Range (traverseLidOrElse(Some exprLeft)) - dive exprRhs exprRhs.Range traverseSynExpr - ] |> pick expr - | SynExpr.Set (exprLeft, exprRhs, _m) -> - [ dive exprLeft exprLeft.Range traverseSynExpr - dive exprRhs exprRhs.Range traverseSynExpr - ] |> pick expr - | SynExpr.NamedIndexedPropertySet (lidwd, exprIndexer, exprRhs, _m) -> - [ dive lidwd lidwd.Range (traverseLidOrElse None) - dive exprIndexer exprIndexer.Range traverseSynExpr - dive exprRhs exprRhs.Range traverseSynExpr - ] |> pick expr - | SynExpr.DotNamedIndexedPropertySet (exprLeft, lidwd, exprIndexer, exprRhs, _m) -> - [ dive exprLeft exprLeft.Range traverseSynExpr - dive lidwd lidwd.Range (traverseLidOrElse(Some exprLeft)) - dive exprIndexer exprIndexer.Range traverseSynExpr - dive exprRhs exprRhs.Range traverseSynExpr - ] |> pick expr - | SynExpr.Const (SynConst.Double(_), m) -> - if posEq m.End pos then - // the cursor is at the dot - Some (m.End, false) - else - // the cursor is left of the dot - None - | SynExpr.DiscardAfterMissingQualificationAfterDot (e, m) -> - match traverseSynExpr e with - | None -> - if posEq m.End pos then - // the cursor is at the dot - Some (e.Range.End, false) - else - // the cursor is left of the dot - None - | r -> r - | SynExpr.App (ExprAtomicFlag.NonAtomic, true, (SynExpr.Ident ident), lhs, _m) - when ident.idText = "op_ArrayLookup" - && not(AstTraversal.rangeContainsPosLeftEdgeInclusive lhs.Range pos) -> - match defaultTraverse expr with - | None -> - // (expr).(expr) is an ML-deprecated array lookup, but we want intellisense on the dot - // also want it for e.g. [|arr|].(0) - Some (lhs.Range.End, false) - | x -> x // we found the answer deeper somewhere in the lhs - | _ -> defaultTraverse expr } - AstTraversal.Traverse(pos, parseTree, walker) - - let GetEntityKind (pos: pos, input: ParsedInput) : EntityKind option = - let (|ConstructorPats|) = function - | Pats ps -> ps - | NamePatPairs(xs, _) -> List.map snd xs - - /// An recursive pattern that collect all sequential expressions to avoid StackOverflowException - let rec (|Sequentials|_|) = function - | SynExpr.Sequential (_, _, e, Sequentials es, _) -> Some (e :: es) - | SynExpr.Sequential (_, _, e1, e2, _) -> Some [e1; e2] - | _ -> None - - let inline isPosInRange range = rangeContainsPos range pos - - let inline ifPosInRange range f = - if isPosInRange range then f() - else None - - let rec walkImplFileInput (ParsedImplFileInput (modules = moduleOrNamespaceList)) = - List.tryPick (walkSynModuleOrNamespace true) moduleOrNamespaceList - - and walkSynModuleOrNamespace isTopLevel (SynModuleOrNamespace(_, _, _, decls, _, Attributes attrs, _, r)) = - List.tryPick walkAttribute attrs - |> Option.orElse (ifPosInRange r (fun _ -> List.tryPick (walkSynModuleDecl isTopLevel) decls)) - - and walkAttribute (attr: SynAttribute) = - if isPosInRange attr.Range then Some EntityKind.Attribute else None - |> Option.orElse (walkExprWithKind (Some EntityKind.Type) attr.ArgExpr) - - and walkTypar (Typar (ident, _, _)) = ifPosInRange ident.idRange (fun _ -> Some EntityKind.Type) - - and walkTyparDecl (SynTyparDecl.TyparDecl (Attributes attrs, typar)) = - List.tryPick walkAttribute attrs - |> Option.orElse (walkTypar typar) - - and walkTypeConstraint = function - | SynTypeConstraint.WhereTyparDefaultsToType (t1, t2, _) -> walkTypar t1 |> Option.orElse (walkType t2) - | SynTypeConstraint.WhereTyparIsValueType(t, _) -> walkTypar t - | SynTypeConstraint.WhereTyparIsReferenceType(t, _) -> walkTypar t - | SynTypeConstraint.WhereTyparIsUnmanaged(t, _) -> walkTypar t - | SynTypeConstraint.WhereTyparSupportsNull (t, _) -> walkTypar t - | SynTypeConstraint.WhereTyparIsComparable(t, _) -> walkTypar t - | SynTypeConstraint.WhereTyparIsEquatable(t, _) -> walkTypar t - | SynTypeConstraint.WhereTyparSubtypeOfType(t, ty, _) -> walkTypar t |> Option.orElse (walkType ty) - | SynTypeConstraint.WhereTyparSupportsMember(ts, sign, _) -> - List.tryPick walkType ts |> Option.orElse (walkMemberSig sign) - | SynTypeConstraint.WhereTyparIsEnum(t, ts, _) -> walkTypar t |> Option.orElse (List.tryPick walkType ts) - | SynTypeConstraint.WhereTyparIsDelegate(t, ts, _) -> walkTypar t |> Option.orElse (List.tryPick walkType ts) - - and walkPatWithKind (kind: EntityKind option) = function - | SynPat.Ands (pats, _) -> List.tryPick walkPat pats - | SynPat.Named(SynPat.Wild nameRange as pat, _, _, _, _) -> - if isPosInRange nameRange then None - else walkPat pat - | SynPat.Typed(pat, t, _) -> walkPat pat |> Option.orElse (walkType t) - | SynPat.Attrib(pat, Attributes attrs, _) -> walkPat pat |> Option.orElse (List.tryPick walkAttribute attrs) - | SynPat.Or(pat1, pat2, _) -> List.tryPick walkPat [pat1; pat2] - | SynPat.LongIdent(_, _, typars, ConstructorPats pats, _, r) -> - ifPosInRange r (fun _ -> kind) - |> Option.orElse ( - typars - |> Option.bind (fun (SynValTyparDecls (typars, _, constraints)) -> - List.tryPick walkTyparDecl typars - |> Option.orElse (List.tryPick walkTypeConstraint constraints))) - |> Option.orElse (List.tryPick walkPat pats) - | SynPat.Tuple(_, pats, _) -> List.tryPick walkPat pats - | SynPat.Paren(pat, _) -> walkPat pat - | SynPat.ArrayOrList(_, pats, _) -> List.tryPick walkPat pats - | SynPat.IsInst(t, _) -> walkType t - | SynPat.QuoteExpr(e, _) -> walkExpr e - | _ -> None - - and walkPat = walkPatWithKind None - - and walkBinding (SynBinding.Binding(_, _, _, _, Attributes attrs, _, _, pat, returnInfo, e, _, _)) = - List.tryPick walkAttribute attrs - |> Option.orElse (walkPat pat) - |> Option.orElse (walkExpr e) - |> Option.orElse ( - match returnInfo with - | Some (SynBindingReturnInfo (t, _, _)) -> walkType t - | None -> None) - - and walkInterfaceImpl (InterfaceImpl(_, bindings, _)) = - List.tryPick walkBinding bindings - - and walkIndexerArg = function - | SynIndexerArg.One (e, _, _) -> walkExpr e - | SynIndexerArg.Two(e1, _, e2, _, _, _) -> List.tryPick walkExpr [e1; e2] - - and walkType = function - | SynType.LongIdent ident -> - // we protect it with try..with because System.Exception : rangeOfLidwd may raise - // at FSharp.Compiler.SyntaxTree.LongIdentWithDots.get_Range() in D:\j\workspace\release_ci_pa---3f142ccc\src\fsharp\ast.fs: line 156 - try ifPosInRange ident.Range (fun _ -> Some EntityKind.Type) with _ -> None - | SynType.App(ty, _, types, _, _, _, _) -> - walkType ty |> Option.orElse (List.tryPick walkType types) - | SynType.LongIdentApp(_, _, _, types, _, _, _) -> List.tryPick walkType types - | SynType.Tuple(_, ts, _) -> ts |> List.tryPick (fun (_, t) -> walkType t) - | SynType.Array(_, t, _) -> walkType t - | SynType.Fun(t1, t2, _) -> walkType t1 |> Option.orElse (walkType t2) - | SynType.WithGlobalConstraints(t, _, _) -> walkType t - | SynType.HashConstraint(t, _) -> walkType t - | SynType.MeasureDivide(t1, t2, _) -> walkType t1 |> Option.orElse (walkType t2) - | SynType.MeasurePower(t, _, _) -> walkType t - | SynType.Paren(t, _) -> walkType t - | _ -> None - - and walkClause (Clause(pat, e1, e2, _, _)) = - walkPatWithKind (Some EntityKind.Type) pat - |> Option.orElse (walkExpr e2) - |> Option.orElse (Option.bind walkExpr e1) - - and walkExprWithKind (parentKind: EntityKind option) = function - | SynExpr.LongIdent (_, LongIdentWithDots(_, dotRanges), _, r) -> - match dotRanges with - | [] when isPosInRange r -> parentKind |> Option.orElse (Some (EntityKind.FunctionOrValue false)) - | firstDotRange :: _ -> - let firstPartRange = - mkRange "" r.Start (mkPos firstDotRange.StartLine (firstDotRange.StartColumn - 1)) - if isPosInRange firstPartRange then - parentKind |> Option.orElse (Some (EntityKind.FunctionOrValue false)) - else None - | _ -> None - | SynExpr.Paren (e, _, _, _) -> walkExprWithKind parentKind e - | SynExpr.Quote (_, _, e, _, _) -> walkExprWithKind parentKind e - | SynExpr.Typed (e, _, _, _) -> walkExprWithKind parentKind e - | SynExpr.Tuple (_, es, _, _) -> List.tryPick (walkExprWithKind parentKind) es - | SynExpr.ArrayOrList (_, es, _) -> List.tryPick (walkExprWithKind parentKind) es - | SynExpr.Record (_, _, fields, r) -> - ifPosInRange r (fun _ -> - fields |> List.tryPick (fun (_, e, _) -> e |> Option.bind (walkExprWithKind parentKind))) - | SynExpr.New (_, t, e, _) -> walkExprWithKind parentKind e |> Option.orElse (walkType t) - | SynExpr.ObjExpr (ty, _, bindings, ifaces, _, _) -> - walkType ty - |> Option.orElse (List.tryPick walkBinding bindings) - |> Option.orElse (List.tryPick walkInterfaceImpl ifaces) - | SynExpr.While (_, e1, e2, _) -> List.tryPick (walkExprWithKind parentKind) [e1; e2] - | SynExpr.For (_, _, e1, _, e2, e3, _) -> List.tryPick (walkExprWithKind parentKind) [e1; e2; e3] - | SynExpr.ForEach (_, _, _, _, e1, e2, _) -> List.tryPick (walkExprWithKind parentKind) [e1; e2] - | SynExpr.ArrayOrListOfSeqExpr (_, e, _) -> walkExprWithKind parentKind e - | SynExpr.CompExpr (_, _, e, _) -> walkExprWithKind parentKind e - | SynExpr.Lambda (_, _, _, e, _, _) -> walkExprWithKind parentKind e - | SynExpr.MatchLambda (_, _, synMatchClauseList, _, _) -> - List.tryPick walkClause synMatchClauseList - | SynExpr.Match (_, e, synMatchClauseList, _) -> - walkExprWithKind parentKind e |> Option.orElse (List.tryPick walkClause synMatchClauseList) - | SynExpr.Do (e, _) -> walkExprWithKind parentKind e - | SynExpr.Assert (e, _) -> walkExprWithKind parentKind e - | SynExpr.App (_, _, e1, e2, _) -> List.tryPick (walkExprWithKind parentKind) [e1; e2] - | SynExpr.TypeApp (e, _, tys, _, _, _, _) -> - walkExprWithKind (Some EntityKind.Type) e |> Option.orElse (List.tryPick walkType tys) - | SynExpr.LetOrUse (_, _, bindings, e, _) -> List.tryPick walkBinding bindings |> Option.orElse (walkExprWithKind parentKind e) - | SynExpr.TryWith (e, _, clauses, _, _, _, _) -> walkExprWithKind parentKind e |> Option.orElse (List.tryPick walkClause clauses) - | SynExpr.TryFinally (e1, e2, _, _, _) -> List.tryPick (walkExprWithKind parentKind) [e1; e2] - | SynExpr.Lazy (e, _) -> walkExprWithKind parentKind e - | Sequentials es -> List.tryPick (walkExprWithKind parentKind) es - | SynExpr.IfThenElse (e1, e2, e3, _, _, _, _) -> - List.tryPick (walkExprWithKind parentKind) [e1; e2] |> Option.orElse (match e3 with None -> None | Some e -> walkExprWithKind parentKind e) - | SynExpr.Ident ident -> ifPosInRange ident.idRange (fun _ -> Some (EntityKind.FunctionOrValue false)) - | SynExpr.LongIdentSet (_, e, _) -> walkExprWithKind parentKind e - | SynExpr.DotGet (e, _, _, _) -> walkExprWithKind parentKind e - | SynExpr.DotSet (e, _, _, _) -> walkExprWithKind parentKind e - | SynExpr.Set (e, _, _) -> walkExprWithKind parentKind e - | SynExpr.DotIndexedGet (e, args, _, _) -> walkExprWithKind parentKind e |> Option.orElse (List.tryPick walkIndexerArg args) - | SynExpr.DotIndexedSet (e, args, _, _, _, _) -> walkExprWithKind parentKind e |> Option.orElse (List.tryPick walkIndexerArg args) - | SynExpr.NamedIndexedPropertySet (_, e1, e2, _) -> List.tryPick (walkExprWithKind parentKind) [e1; e2] - | SynExpr.DotNamedIndexedPropertySet (e1, _, e2, e3, _) -> List.tryPick (walkExprWithKind parentKind) [e1; e2; e3] - | SynExpr.TypeTest (e, t, _) -> walkExprWithKind parentKind e |> Option.orElse (walkType t) - | SynExpr.Upcast (e, t, _) -> walkExprWithKind parentKind e |> Option.orElse (walkType t) - | SynExpr.Downcast (e, t, _) -> walkExprWithKind parentKind e |> Option.orElse (walkType t) - | SynExpr.InferredUpcast (e, _) -> walkExprWithKind parentKind e - | SynExpr.InferredDowncast (e, _) -> walkExprWithKind parentKind e - | SynExpr.AddressOf (_, e, _, _) -> walkExprWithKind parentKind e - | SynExpr.JoinIn (e1, _, e2, _) -> List.tryPick (walkExprWithKind parentKind) [e1; e2] - | SynExpr.YieldOrReturn (_, e, _) -> walkExprWithKind parentKind e - | SynExpr.YieldOrReturnFrom (_, e, _) -> walkExprWithKind parentKind e - | SynExpr.Match (_, e, synMatchClauseList, _) - | SynExpr.MatchBang (_, e, synMatchClauseList, _) -> - walkExprWithKind parentKind e |> Option.orElse (List.tryPick walkClause synMatchClauseList) - | SynExpr.LetOrUseBang(_, _, _, _, e1, es, e2, _) -> - [ - yield e1 - for (_,_,_,_,eAndBang,_) in es do - yield eAndBang - yield e2 - ] - |> List.tryPick (walkExprWithKind parentKind) - | SynExpr.DoBang (e, _) -> walkExprWithKind parentKind e - | SynExpr.TraitCall (ts, sign, e, _) -> - List.tryPick walkTypar ts - |> Option.orElse (walkMemberSig sign) - |> Option.orElse (walkExprWithKind parentKind e) - | _ -> None - - and walkExpr = walkExprWithKind None - - and walkSimplePat = function - | SynSimplePat.Attrib (pat, Attributes attrs, _) -> - walkSimplePat pat |> Option.orElse (List.tryPick walkAttribute attrs) - | SynSimplePat.Typed(pat, t, _) -> walkSimplePat pat |> Option.orElse (walkType t) - | _ -> None - - and walkField (SynField.Field(Attributes attrs, _, _, t, _, _, _, _)) = - List.tryPick walkAttribute attrs |> Option.orElse (walkType t) - - and walkValSig (SynValSig.ValSpfn(Attributes attrs, _, _, t, _, _, _, _, _, _, _)) = - List.tryPick walkAttribute attrs |> Option.orElse (walkType t) - - and walkMemberSig = function - | SynMemberSig.Inherit (t, _) -> walkType t - | SynMemberSig.Member(vs, _, _) -> walkValSig vs - | SynMemberSig.Interface(t, _) -> walkType t - | SynMemberSig.ValField(f, _) -> walkField f - | SynMemberSig.NestedType(SynTypeDefnSig.TypeDefnSig (info, repr, memberSigs, _), _) -> - walkComponentInfo false info - |> Option.orElse (walkTypeDefnSigRepr repr) - |> Option.orElse (List.tryPick walkMemberSig memberSigs) - - and walkMember = function - | SynMemberDefn.AbstractSlot (valSig, _, _) -> walkValSig valSig - | SynMemberDefn.Member(binding, _) -> walkBinding binding - | SynMemberDefn.ImplicitCtor(_, Attributes attrs, SynSimplePats.SimplePats(simplePats, _), _, _, _) -> - List.tryPick walkAttribute attrs |> Option.orElse (List.tryPick walkSimplePat simplePats) - | SynMemberDefn.ImplicitInherit(t, e, _, _) -> walkType t |> Option.orElse (walkExpr e) - | SynMemberDefn.LetBindings(bindings, _, _, _) -> List.tryPick walkBinding bindings - | SynMemberDefn.Interface(t, members, _) -> - walkType t |> Option.orElse (members |> Option.bind (List.tryPick walkMember)) - | SynMemberDefn.Inherit(t, _, _) -> walkType t - | SynMemberDefn.ValField(field, _) -> walkField field - | SynMemberDefn.NestedType(tdef, _, _) -> walkTypeDefn tdef - | SynMemberDefn.AutoProperty(Attributes attrs, _, _, t, _, _, _, _, e, _, _) -> - List.tryPick walkAttribute attrs - |> Option.orElse (Option.bind walkType t) - |> Option.orElse (walkExpr e) - | _ -> None - - and walkEnumCase (EnumCase(Attributes attrs, _, _, _, _)) = List.tryPick walkAttribute attrs - - and walkUnionCaseType = function - | SynUnionCaseType.UnionCaseFields fields -> List.tryPick walkField fields - | SynUnionCaseType.UnionCaseFullType(t, _) -> walkType t - - and walkUnionCase (UnionCase(Attributes attrs, _, t, _, _, _)) = - List.tryPick walkAttribute attrs |> Option.orElse (walkUnionCaseType t) - - and walkTypeDefnSimple = function - | SynTypeDefnSimpleRepr.Enum (cases, _) -> List.tryPick walkEnumCase cases - | SynTypeDefnSimpleRepr.Union(_, cases, _) -> List.tryPick walkUnionCase cases - | SynTypeDefnSimpleRepr.Record(_, fields, _) -> List.tryPick walkField fields - | SynTypeDefnSimpleRepr.TypeAbbrev(_, t, _) -> walkType t - | _ -> None - - and walkComponentInfo isModule (ComponentInfo(Attributes attrs, typars, constraints, _, _, _, _, r)) = - if isModule then None else ifPosInRange r (fun _ -> Some EntityKind.Type) - |> Option.orElse ( - List.tryPick walkAttribute attrs - |> Option.orElse (List.tryPick walkTyparDecl typars) - |> Option.orElse (List.tryPick walkTypeConstraint constraints)) - - and walkTypeDefnRepr = function - | SynTypeDefnRepr.ObjectModel (_, defns, _) -> List.tryPick walkMember defns - | SynTypeDefnRepr.Simple(defn, _) -> walkTypeDefnSimple defn - | SynTypeDefnRepr.Exception(_) -> None - - and walkTypeDefnSigRepr = function - | SynTypeDefnSigRepr.ObjectModel (_, defns, _) -> List.tryPick walkMemberSig defns - | SynTypeDefnSigRepr.Simple(defn, _) -> walkTypeDefnSimple defn - | SynTypeDefnSigRepr.Exception(_) -> None - - and walkTypeDefn (TypeDefn (info, repr, members, _, _)) = - walkComponentInfo false info - |> Option.orElse (walkTypeDefnRepr repr) - |> Option.orElse (List.tryPick walkMember members) - - and walkSynModuleDecl isTopLevel (decl: SynModuleDecl) = - match decl with - | SynModuleDecl.NamespaceFragment fragment -> walkSynModuleOrNamespace isTopLevel fragment - | SynModuleDecl.NestedModule(info, _, modules, _, range) -> - walkComponentInfo true info - |> Option.orElse (ifPosInRange range (fun _ -> List.tryPick (walkSynModuleDecl false) modules)) - | SynModuleDecl.Open _ -> None - | SynModuleDecl.Let (_, bindings, _) -> List.tryPick walkBinding bindings - | SynModuleDecl.DoExpr (_, expr, _) -> walkExpr expr - | SynModuleDecl.Types (types, _) -> List.tryPick walkTypeDefn types - | _ -> None - - match input with - | ParsedInput.SigFile _ -> None - | ParsedInput.ImplFile input -> walkImplFileInput input - - type internal TS = AstTraversal.TraverseStep - /// Matches the most nested [< and >] pair. - let insideAttributeApplicationRegex = Regex(@"(?<=\[\<)(?(.*?))(?=\>\])", RegexOptions.Compiled ||| RegexOptions.ExplicitCapture) - - /// Try to determine completion context for the given pair (row, columns) - let TryGetCompletionContext (pos, parsedInput: ParsedInput, lineStr: string) : CompletionContext option = - - match GetEntityKind(pos, parsedInput) with - | Some EntityKind.Attribute -> Some CompletionContext.AttributeApplication - | _ -> - - let parseLid (LongIdentWithDots(lid, dots)) = - let rec collect plid (parts : Ident list) (dots : range list) = - match parts, dots with - | [], _ -> Some (plid, None) - | x :: xs, ds -> - if rangeContainsPos x.idRange pos then - // pos lies with the range of current identifier - let s = x.idText.Substring(0, pos.Column - x.idRange.Start.Column) - let residue = if s.Length <> 0 then Some s else None - Some (plid, residue) - elif posGt x.idRange.Start pos then - // can happen if caret is placed after dot but before the existing identifier A. $ B - // return accumulated plid with no residue - Some (plid, None) - else - match ds with - | [] -> - // pos lies after the id and no dots found - return accumulated plid and current id as residue - Some (plid, Some (x.idText)) - | d :: ds -> - if posGeq pos d.End then - // pos lies after the dot - proceed to the next identifier - collect ((x.idText) :: plid) xs ds - else - // pos after the id but before the dot - // A $.B - return nothing - None - - match collect [] lid dots with - | Some (parts, residue) -> - Some ((List.rev parts), residue) - | None -> None - - let (|Class|Interface|Struct|Unknown|Invalid|) synAttributes = - let (|SynAttr|_|) name (attr : SynAttribute) = - match attr with - | {TypeName = LongIdentWithDots([x], _)} when x.idText = name -> Some () - | _ -> None - - let rec getKind isClass isInterface isStruct = - function - | [] -> isClass, isInterface, isStruct - | (SynAttr "Class") :: xs -> getKind true isInterface isStruct xs - | (SynAttr "AbstractClass") :: xs -> getKind true isInterface isStruct xs - | (SynAttr "Interface") :: xs -> getKind isClass true isStruct xs - | (SynAttr "Struct") :: xs -> getKind isClass isInterface true xs - | _ :: xs -> getKind isClass isInterface isStruct xs - - match getKind false false false synAttributes with - | false, false, false -> Unknown - | true, false, false -> Class - | false, true, false -> Interface - | false, false, true -> Struct - | _ -> Invalid - - let GetCompletionContextForInheritSynMember ((ComponentInfo(Attributes synAttributes, _, _, _, _, _, _, _)), typeDefnKind : SynTypeDefnKind, completionPath) = - - let success k = Some (CompletionContext.Inherit (k, completionPath)) - - // if kind is specified - take it - // if kind is non-specified - // - try to obtain it from attribute - // - if no attributes present - infer kind from members - match typeDefnKind with - | TyconClass -> - match synAttributes with - | Class | Unknown -> success InheritanceContext.Class - | _ -> Some CompletionContext.Invalid // non-matching attributes - | TyconInterface -> - match synAttributes with - | Interface | Unknown -> success InheritanceContext.Interface - | _ -> Some CompletionContext.Invalid // non-matching attributes - | TyconStruct -> - // display nothing for structs - Some CompletionContext.Invalid - | TyconUnspecified -> - match synAttributes with - | Class -> success InheritanceContext.Class - | Interface -> success InheritanceContext.Interface - | Unknown -> - // user do not specify kind explicitly or via attributes - success InheritanceContext.Unknown - | _ -> - // unable to uniquely detect kind from the attributes - return invalid context - Some CompletionContext.Invalid - | _ -> None - - let (|Operator|_|) name e = - match e with - | SynExpr.App (ExprAtomicFlag.NonAtomic, false, SynExpr.App (ExprAtomicFlag.NonAtomic, true, SynExpr.Ident ident, lhs, _), rhs, _) - when ident.idText = name -> Some (lhs, rhs) - | _ -> None - - // checks if we are in rhs of the range operator - let isInRhsOfRangeOp (p : AstTraversal.TraversePath) = - match p with - | TS.Expr(Operator "op_Range" _) :: _ -> true - | _ -> false - - let (|Setter|_|) e = - match e with - | Operator "op_Equality" (SynExpr.Ident id, _) -> Some id - | _ -> None - - let findSetters argList = - match argList with - | SynExpr.Paren (SynExpr.Tuple (false, parameters, _, _), _, _, _) -> - let setters = HashSet() - for p in parameters do - match p with - | Setter id -> ignore(setters.Add id.idText) - | _ -> () - setters - | _ -> emptyStringSet - - let endOfLastIdent (lid: LongIdentWithDots) = - let last = List.last lid.Lid - last.idRange.End - - let endOfClosingTokenOrLastIdent (mClosing: range option) (lid : LongIdentWithDots) = - match mClosing with - | Some m -> m.End - | None -> endOfLastIdent lid - - let endOfClosingTokenOrIdent (mClosing: range option) (id : Ident) = - match mClosing with - | Some m -> m.End - | None -> id.idRange.End - - let (|NewObjectOrMethodCall|_|) e = - match e with - | (SynExpr.New (_, SynType.LongIdent typeName, arg, _)) -> - // new A() - Some (endOfLastIdent typeName, findSetters arg) - | (SynExpr.New (_, SynType.App(StripParenTypes (SynType.LongIdent typeName), _, _, _, mGreaterThan, _, _), arg, _)) -> - // new A<_>() - Some (endOfClosingTokenOrLastIdent mGreaterThan typeName, findSetters arg) - | (SynExpr.App (_, false, SynExpr.Ident id, arg, _)) -> - // A() - Some (id.idRange.End, findSetters arg) - | (SynExpr.App (_, false, SynExpr.TypeApp (SynExpr.Ident id, _, _, _, mGreaterThan, _, _), arg, _)) -> - // A<_>() - Some (endOfClosingTokenOrIdent mGreaterThan id, findSetters arg) - | (SynExpr.App (_, false, SynExpr.LongIdent (_, lid, _, _), arg, _)) -> - // A.B() - Some (endOfLastIdent lid, findSetters arg) - | (SynExpr.App (_, false, SynExpr.TypeApp (SynExpr.LongIdent (_, lid, _, _), _, _, _, mGreaterThan, _, _), arg, _)) -> - // A.B<_>() - Some (endOfClosingTokenOrLastIdent mGreaterThan lid, findSetters arg) - | _ -> None - - let isOnTheRightOfComma (elements: SynExpr list) (commas: range list) current = - let rec loop elements (commas: range list) = - match elements with - | x :: xs -> - match commas with - | c :: cs -> - if x === current then posLt c.End pos || posEq c.End pos - else loop xs cs - | _ -> false - | _ -> false - loop elements commas - - let (|PartOfParameterList|_|) precedingArgument path = - match path with - | TS.Expr(SynExpr.Paren _) :: TS.Expr(NewObjectOrMethodCall args) :: _ -> - if Option.isSome precedingArgument then None else Some args - | TS.Expr(SynExpr.Tuple (false, elements, commas, _)) :: TS.Expr(SynExpr.Paren _) :: TS.Expr(NewObjectOrMethodCall args) :: _ -> - match precedingArgument with - | None -> Some args - | Some e -> - // if expression is passed then - // 1. find it in among elements of the tuple - // 2. find corresponding comma - // 3. check that current position is past the comma - // this is used for cases like (a = something-here.) if the cursor is after . - // in this case this is not object initializer completion context - if isOnTheRightOfComma elements commas e then Some args else None - | _ -> None - - let walker = - { - new AstTraversal.AstVisitorBase<_>() with - member _.VisitExpr(path, _, defaultTraverse, expr) = - - if isInRhsOfRangeOp path then - match defaultTraverse expr with - | None -> Some CompletionContext.RangeOperator // nothing was found - report that we were in the context of range operator - | x -> x // ok, we found something - return it - else - match expr with - // new A($) - | SynExpr.Const (SynConst.Unit, m) when rangeContainsPos m pos -> - match path with - | TS.Expr(NewObjectOrMethodCall args) :: _ -> - Some (CompletionContext.ParameterList args) - | _ -> - defaultTraverse expr - // new (... A$) - | SynExpr.Ident id when id.idRange.End = pos -> - match path with - | PartOfParameterList None args -> - Some (CompletionContext.ParameterList args) - | _ -> - defaultTraverse expr - // new (A$ = 1) - // new (A = 1, $) - | Setter id when id.idRange.End = pos || rangeBeforePos expr.Range pos -> - let precedingArgument = if id.idRange.End = pos then None else Some expr - match path with - | PartOfParameterList precedingArgument args-> - Some (CompletionContext.ParameterList args) - | _ -> - defaultTraverse expr - - | _ -> defaultTraverse expr - - member _.VisitRecordField(path, copyOpt, field) = - let contextFromTreePath completionPath = - // detect records usage in constructor - match path with - | TS.Expr(_) :: TS.Binding(_) :: TS.MemberDefn(_) :: TS.TypeDefn(SynTypeDefn.TypeDefn(ComponentInfo(_, _, _, [id], _, _, _, _), _, _, _, _)) :: _ -> - RecordContext.Constructor(id.idText) - | _ -> RecordContext.New completionPath - match field with - | Some field -> - match parseLid field with - | Some completionPath -> - let recordContext = - match copyOpt with - | Some (s : SynExpr) -> RecordContext.CopyOnUpdate(s.Range, completionPath) - | None -> contextFromTreePath completionPath - Some (CompletionContext.RecordField recordContext) - | None -> None - | None -> - let recordContext = - match copyOpt with - | Some s -> RecordContext.CopyOnUpdate(s.Range, ([], None)) - | None -> contextFromTreePath ([], None) - Some (CompletionContext.RecordField recordContext) - - member _.VisitInheritSynMemberDefn(componentInfo, typeDefnKind, synType, _members, _range) = - match synType with - | SynType.LongIdent lidwd -> - match parseLid lidwd with - | Some completionPath -> GetCompletionContextForInheritSynMember (componentInfo, typeDefnKind, completionPath) - | None -> Some (CompletionContext.Invalid) // A $ .B -> no completion list - - | _ -> None - - member _.VisitBinding(defaultTraverse, (Binding(headPat = headPat) as synBinding)) = - - let visitParam = function - | SynPat.Named (range = range) when rangeContainsPos range pos -> - // parameter without type hint, no completion - Some CompletionContext.Invalid - | SynPat.Typed(SynPat.Named(SynPat.Wild range, _, _, _, _), _, _) when rangeContainsPos range pos -> - // parameter with type hint, but we are on its name, no completion - Some CompletionContext.Invalid - | _ -> defaultTraverse synBinding - - match headPat with - | SynPat.LongIdent(longDotId = lidwd) when rangeContainsPos lidwd.Range pos -> - // let fo|o x = () - Some CompletionContext.Invalid - | SynPat.LongIdent(_, _, _, ctorArgs, _, _) -> - match ctorArgs with - | SynArgPats.Pats pats -> - pats |> List.tryPick (fun pat -> - match pat with - | SynPat.Paren(pat, _) -> - match pat with - | SynPat.Tuple(_, pats, _) -> - pats |> List.tryPick visitParam - | _ -> visitParam pat - | SynPat.Wild range when rangeContainsPos range pos -> - // let foo (x| - Some CompletionContext.Invalid - | _ -> visitParam pat - ) - | _ -> defaultTraverse synBinding - | SynPat.Named(range = range) when rangeContainsPos range pos -> - // let fo|o = 1 - Some CompletionContext.Invalid - | _ -> defaultTraverse synBinding - - member _.VisitHashDirective range = - if rangeContainsPos range pos then Some CompletionContext.Invalid - else None - - member _.VisitModuleOrNamespace(SynModuleOrNamespace(longId = idents)) = - match List.tryLast idents with - | Some lastIdent when pos.Line = lastIdent.idRange.EndLine && lastIdent.idRange.EndColumn >= 0 && pos.Column <= lineStr.Length -> - let stringBetweenModuleNameAndPos = lineStr.[lastIdent.idRange.EndColumn..pos.Column - 1] - if stringBetweenModuleNameAndPos |> Seq.forall (fun x -> x = ' ' || x = '.') then - Some CompletionContext.Invalid - else None - | _ -> None - - member _.VisitComponentInfo(ComponentInfo(range = range)) = - if rangeContainsPos range pos then Some CompletionContext.Invalid - else None - - member _.VisitLetOrUse(_, _, bindings, range) = - match bindings with - | [] when range.StartLine = pos.Line -> Some CompletionContext.Invalid - | _ -> None - - member _.VisitSimplePats pats = - pats |> List.tryPick (fun pat -> - match pat with - | SynSimplePat.Id(range = range) - | SynSimplePat.Typed(SynSimplePat.Id(range = range), _, _) when rangeContainsPos range pos -> - Some CompletionContext.Invalid - | _ -> None) - - member _.VisitModuleDecl(defaultTraverse, decl) = - match decl with - | SynModuleDecl.Open(target, m) -> - // in theory, this means we're "in an open" - // in practice, because the parse tree/walkers do not handle attributes well yet, need extra check below to ensure not e.g. $here$ - // open System - // [ true - | SynOpenDeclTarget.ModuleOrNamespace _ -> false - Some (CompletionContext.OpenDeclaration isOpenType) - else - None - | _ -> defaultTraverse decl - - member _.VisitType(defaultTraverse, ty) = - match ty with - | SynType.LongIdent _ when rangeContainsPos ty.Range pos -> - Some CompletionContext.PatternType - | _ -> defaultTraverse ty - } - - AstTraversal.Traverse(pos, parsedInput, walker) - // Uncompleted attribute applications are not presented in the AST in any way. So, we have to parse source string. - |> Option.orElseWith (fun _ -> - let cutLeadingAttributes (str: string) = - // cut off leading attributes, i.e. we cut "[]" to " >]" - match str.LastIndexOf ';' with - | -1 -> str - | idx when idx < str.Length -> str.[idx + 1..].TrimStart() - | _ -> "" - - let isLongIdent = Seq.forall (fun c -> IsIdentifierPartCharacter c || c = '.' || c = ':') // ':' may occur in "[]" - - // match the most nested paired [< and >] first - let matches = - insideAttributeApplicationRegex.Matches lineStr - |> Seq.cast - |> Seq.filter (fun m -> m.Index <= pos.Column && m.Index + m.Length >= pos.Column) - |> Seq.toArray - - if not (Array.isEmpty matches) then - matches - |> Seq.tryPick (fun m -> - let g = m.Groups.["attribute"] - let col = pos.Column - g.Index - if col >= 0 && col < g.Length then - let str = g.Value.Substring(0, col).TrimStart() // cut other rhs attributes - let str = cutLeadingAttributes str - if isLongIdent str then - Some CompletionContext.AttributeApplication - else None - else None) - else - // Paired [< and >] were not found, try to determine that we are after [< without closing >] - match lineStr.LastIndexOf("[<", StringComparison.Ordinal) with - | -1 -> None - | openParenIndex when pos.Column >= openParenIndex + 2 -> - let str = lineStr.[openParenIndex + 2..pos.Column - 1].TrimStart() - let str = cutLeadingAttributes str - if isLongIdent str then - Some CompletionContext.AttributeApplication - else None - | _ -> None) - - /// Check if we are at an "open" declaration - let GetFullNameOfSmallestModuleOrNamespaceAtPoint (parsedInput: ParsedInput, pos: pos) = - let mutable path = [] - let visitor = - { new AstTraversal.AstVisitorBase() with - override this.VisitExpr(_path, _traverseSynExpr, defaultTraverse, expr) = - // don't need to keep going, namespaces and modules never appear inside Exprs - None - override this.VisitModuleOrNamespace(SynModuleOrNamespace(longId = longId; range = range)) = - if rangeContainsPos range pos then - path <- path @ longId - None // we should traverse the rest of the AST to find the smallest module - } - AstTraversal.Traverse(pos, parsedInput, visitor) |> ignore - path |> List.map (fun x -> x.idText) |> List.toArray diff --git a/tests/fsharp/core/auto-widen/preview/test.bsl b/tests/fsharp/core/auto-widen/preview/test.bsl index 89af8192c4c..4c841aeb386 100644 --- a/tests/fsharp/core/auto-widen/preview/test.bsl +++ b/tests/fsharp/core/auto-widen/preview/test.bsl @@ -186,3 +186,32 @@ test.fsx(408,40,408,41): typecheck error FS3386: This expression uses an implici test.fsx(452,32,452,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. test.fsx(454,46,454,47): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +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 FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +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'. + +test.fsx(482,18,482,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +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'. + +test.fsx(482,18,482,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(507,18,507,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(507,18,507,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(519,18,519,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(519,18,519,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(538,18,538,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +test.fsx(538,18,538,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. diff --git a/tests/fsharp/core/auto-widen/preview/test.fsx b/tests/fsharp/core/auto-widen/preview/test.fsx index 1905c5977d0..d4667524d50 100644 --- a/tests/fsharp/core/auto-widen/preview/test.fsx +++ b/tests/fsharp/core/auto-widen/preview/test.fsx @@ -453,6 +453,91 @@ module TestInferObjExprTypeParamFromKNownType = 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 + printfn "test done" let aa = diff --git a/tests/fsharp/tests.fs b/tests/fsharp/tests.fs index 0f6b19a7942..5f173c80fd4 100644 --- a/tests/fsharp/tests.fs +++ b/tests/fsharp/tests.fs @@ -66,7 +66,7 @@ module CoreTests = [] let ``auto-widen-version-preview-warns-on``() = let cfg = testConfig "core/auto-widen/preview" - let cfg = { cfg with fsc_flags = cfg.fsc_flags + " --warnon:3386 --warnaserror+" } + let cfg = { cfg with fsc_flags = cfg.fsc_flags + " --warnon:3386 --warnaserror+ --define:NEGATIVE" } singleVersionedNegTest cfg "preview" "test" [] diff --git a/tests/fsharp/typecheck/sigs/neg20.bsl b/tests/fsharp/typecheck/sigs/neg20.bsl index 75d06ce1332..30b643a9a6a 100644 --- a/tests/fsharp/typecheck/sigs/neg20.bsl +++ b/tests/fsharp/typecheck/sigs/neg20.bsl @@ -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 1574d4d3340..4b0a08e0033 100644 --- a/tests/fsharp/typecheck/sigs/neg20.fs +++ b/tests/fsharp/typecheck/sigs/neg20.fs @@ -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" + From cfb69c42711760f0e74daf46cbc64239d9ee2b8d Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 8 Jun 2021 15:23:01 +0100 Subject: [PATCH 34/42] remove int32 --> float32 and floar32 --> float64, improve error messages --- src/fsharp/FSComp.txt | 8 ++--- src/fsharp/MethodCalls.fs | 16 --------- src/fsharp/xlf/FSComp.txt.cs.xlf | 8 ++--- src/fsharp/xlf/FSComp.txt.de.xlf | 8 ++--- src/fsharp/xlf/FSComp.txt.es.xlf | 8 ++--- src/fsharp/xlf/FSComp.txt.fr.xlf | 8 ++--- src/fsharp/xlf/FSComp.txt.it.xlf | 8 ++--- src/fsharp/xlf/FSComp.txt.ja.xlf | 8 ++--- src/fsharp/xlf/FSComp.txt.ko.xlf | 8 ++--- src/fsharp/xlf/FSComp.txt.pl.xlf | 8 ++--- src/fsharp/xlf/FSComp.txt.pt-BR.xlf | 8 ++--- src/fsharp/xlf/FSComp.txt.ru.xlf | 8 ++--- src/fsharp/xlf/FSComp.txt.tr.xlf | 8 ++--- src/fsharp/xlf/FSComp.txt.zh-Hans.xlf | 8 ++--- src/fsharp/xlf/FSComp.txt.zh-Hant.xlf | 8 ++--- .../Diagnostics/async.fs | 4 +-- .../ElseBranchHasWrongTypeTests.fs | 14 ++++---- .../async/ReturnBangNonAsync_IfThenElse.fs | 2 +- tests/fsharp/core/auto-widen/5.0/test.bsl | 36 +++++++++---------- tests/fsharp/core/auto-widen/preview/test.bsl | 27 ++++++++------ tests/fsharp/core/auto-widen/preview/test.fsx | 9 +++-- tests/fsharp/typecheck/sigs/neg20.bsl | 18 +++++----- tests/fsharp/typecheck/sigs/neg24.bsl | 4 +-- tests/fsharp/typecheck/sigs/neg24.fs | 2 +- tests/fsharp/typecheck/sigs/neg80.vsbsl | 2 +- .../fsharp/typecheck/sigs/version47/neg24.bsl | 4 +-- .../fsharp/typecheck/sigs/version47/neg24.fs | 2 +- .../fsharp/typecheck/sigs/version50/neg20.bsl | 18 +++++----- .../async/ReturnBangNonAsync_IfThenElse.fs | 2 +- 29 files changed, 134 insertions(+), 138 deletions(-) diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 90d429813f4..d07c94d830c 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." diff --git a/src/fsharp/MethodCalls.fs b/src/fsharp/MethodCalls.fs index acd08624cd2..3643a31ff47 100644 --- a/src/fsharp/MethodCalls.fs +++ b/src/fsharp/MethodCalls.fs @@ -264,18 +264,10 @@ let rec AdjustRequiredTypeForTypeDirectedConversions (infoReader: InfoReader) ad 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), None - // Adhoc int32 --> float32 - elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.float32_ty reqdTy && typeEquiv g g.int32_ty actualTy then - g.int32_ty, TypeDirectedConversionUsed.Yes(warn), 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), None - // Adhoc float32--> float64 - elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.float32_ty actualTy then - g.float32_ty, TypeDirectedConversionUsed.Yes(warn), 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 @@ -1212,18 +1204,10 @@ let rec AdjustExprForTypeDirectedConversions tcVal (g: TcGlobals) amap infoReade 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 --> float32 - elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.float32_ty reqdTy && typeEquiv g g.int32_ty actualTy then - mkCallToSingleOperator 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 - // Adhoc float32 --> float64 - elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.float32_ty actualTy then - mkCallToDoubleOperator g m actualTy expr - else match TryFindRelevantImplicitConversion infoReader ad reqdTy actualTy m with | Some (minfo, _) -> diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index bb1a9625870..e65cf9c033b 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -553,12 +553,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}. @@ -573,12 +573,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 16be744711d..deaf3d5b3b6 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -553,12 +553,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. @@ -573,12 +573,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 6cd7a6782bf..2a038a91aa5 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -553,12 +553,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}". @@ -573,12 +573,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 c41418ed879..b2f322b1c2d 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -553,12 +553,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}'. @@ -573,12 +573,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 649a5747a66..7fc7bfbf0fe 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -553,12 +553,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}'. @@ -573,12 +573,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 715c273a7f0..680547cc677 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -548,12 +548,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}' になっています。 @@ -568,12 +568,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 f71f202cf3c..5e2db3b3971 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -553,12 +553,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}' 형식이 지정되었습니다. @@ -573,12 +573,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 4cd1217d8e0..970a4fe1616 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -553,12 +553,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}”. @@ -573,12 +573,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 5c08d95ed46..e4e9d5981b4 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -553,12 +553,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}'. @@ -573,12 +573,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 0df1b43ce6f..b03506d51f3 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -553,12 +553,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}". @@ -573,12 +573,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 57c68489841..0c3085f6c75 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -553,12 +553,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. @@ -573,12 +573,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 5ab07e3a7d4..cbe4b09902a 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -553,12 +553,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}”。 @@ -573,12 +573,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 81db5c0ada0..cff8d1f3ed9 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -553,12 +553,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}'。 @@ -573,12 +573,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 ffcea4feb3f..4990302b72f 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 e986cc6b722..7cbb911248e 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/core/auto-widen/5.0/test.bsl b/tests/fsharp/core/auto-widen/5.0/test.bsl index c5f56d7234b..d7d611dd20d 100644 --- a/tests/fsharp/core/auto-widen/5.0/test.bsl +++ b/tests/fsharp/core/auto-widen/5.0/test.bsl @@ -94,33 +94,33 @@ test.fsx(60,28,60,29): typecheck error FS0001: This expression was expected to h but here has type 'int' -test.fsx(60,30,60,31): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'int64'. This element 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 of the same type as 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 of the same type as 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 of the same type as the first element, which here is 'float'. This element 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 of the same type as 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 of the same type as 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 of the same type as the first element, which here is 'float32'. This element 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 of the same type as 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 of the same type as 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' @@ -132,7 +132,7 @@ test.fsx(64,28,64,49): typecheck error FS0001: This expression was expected to h but here has type 'int' -test.fsx(64,50,64,71): typecheck error FS0001: All elements of a list must be of the same type as the first element, which here is 'int64'. This element 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' @@ -424,9 +424,9 @@ test.fsx(246,45,246,46): typecheck error FS0001: This expression was expected to but here has type 'int' -test.fsx(246,54,246,57): typecheck error FS0001: All branches of a pattern match expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. +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 of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'byte'. +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' @@ -585,17 +585,17 @@ but here has type 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 of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. +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 of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. +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 of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'byte'. +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 of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. +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' @@ -617,7 +617,7 @@ test.fsx(306,45,306,46): typecheck error FS0001: This expression was expected to but here has type 'int' -test.fsx(306,54,306,57): typecheck error FS0001: All branches of a pattern match expression must return values of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. +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' @@ -626,7 +626,7 @@ but here has type 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 of the same type as the first branch, which here is 'obj'. This branch returns a value of type 'float'. +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' diff --git a/tests/fsharp/core/auto-widen/preview/test.bsl b/tests/fsharp/core/auto-widen/preview/test.bsl index 4c841aeb386..a323bb59aa4 100644 --- a/tests/fsharp/core/auto-widen/preview/test.bsl +++ b/tests/fsharp/core/auto-widen/preview/test.bsl @@ -17,16 +17,6 @@ test.fsx(61,30,61,31): typecheck error FS3386: This expression uses an implicit test.fsx(61,32,61,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(61,34,61,35): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - -test.fsx(62,30,62,31): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float32'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - -test.fsx(62,32,62,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float32'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - -test.fsx(62,34,62,35): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float32'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - -test.fsx(62,36,62,37): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float32'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - test.fsx(63,22,63,43): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. test.fsx(64,28,64,49): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. @@ -215,3 +205,20 @@ test.fsx(519,18,519,21): typecheck error FS3386: This expression uses an implici test.fsx(538,18,538,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. test.fsx(538,18,538,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + +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 \ No newline at end of file diff --git a/tests/fsharp/core/auto-widen/preview/test.fsx b/tests/fsharp/core/auto-widen/preview/test.fsx index d4667524d50..548f9081db6 100644 --- a/tests/fsharp/core/auto-widen/preview/test.fsx +++ b/tests/fsharp/core/auto-widen/preview/test.fsx @@ -58,8 +58,8 @@ module IntegerWidening = 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 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 @@ -538,6 +538,11 @@ module TestExtrinsicOpImplicitIgnoredCompletely = 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 = diff --git a/tests/fsharp/typecheck/sigs/neg20.bsl b/tests/fsharp/typecheck/sigs/neg20.bsl index 30b643a9a6a..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' diff --git a/tests/fsharp/typecheck/sigs/neg24.bsl b/tests/fsharp/typecheck/sigs/neg24.bsl index ffc702de46b..03d8ce84002 100644 --- a/tests/fsharp/typecheck/sigs/neg24.bsl +++ b/tests/fsharp/typecheck/sigs/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/neg24.fs b/tests/fsharp/typecheck/sigs/neg24.fs index 6e1e072cf1a..38cb01cf2d2 100644 --- a/tests/fsharp/typecheck/sigs/neg24.fs +++ b/tests/fsharp/typecheck/sigs/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/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 index 75d06ce1332..88d816d6644 100644 --- a/tests/fsharp/typecheck/sigs/version50/neg20.bsl +++ b/tests/fsharp/typecheck/sigs/version50/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' 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 From 5152b79b41b19a79d5687153a1bd4e5dd82c27a7 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 6 Jul 2021 14:15:35 +0100 Subject: [PATCH 35/42] update baseline and improve errors --- src/fsharp/CheckExpressions.fs | 7 +-- src/fsharp/FSComp.txt | 3 +- src/fsharp/MethodCalls.fs | 31 ++++++++--- src/fsharp/NicePrint.fs | 10 +++- src/fsharp/NicePrint.fsi | 4 +- src/fsharp/xlf/FSComp.txt.cs.xlf | 9 +++- src/fsharp/xlf/FSComp.txt.de.xlf | 9 +++- src/fsharp/xlf/FSComp.txt.es.xlf | 9 +++- src/fsharp/xlf/FSComp.txt.fr.xlf | 9 +++- src/fsharp/xlf/FSComp.txt.it.xlf | 9 +++- src/fsharp/xlf/FSComp.txt.ja.xlf | 9 +++- src/fsharp/xlf/FSComp.txt.ko.xlf | 9 +++- src/fsharp/xlf/FSComp.txt.pl.xlf | 9 +++- src/fsharp/xlf/FSComp.txt.pt-BR.xlf | 9 +++- src/fsharp/xlf/FSComp.txt.ru.xlf | 9 +++- src/fsharp/xlf/FSComp.txt.tr.xlf | 9 +++- src/fsharp/xlf/FSComp.txt.zh-Hans.xlf | 9 +++- src/fsharp/xlf/FSComp.txt.zh-Hant.xlf | 9 +++- tests/fsharp/core/auto-widen/preview/test.bsl | 54 ++++++++++--------- 19 files changed, 160 insertions(+), 66 deletions(-) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 10e4807a72d..b14c995f86e 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -10158,12 +10158,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" System.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/FSComp.txt b/src/fsharp/FSComp.txt index ff48ded92fd..5eda5f5f5bf 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1556,7 +1556,8 @@ forFormatInvalidForInterpolated4,"Interpolated strings used as type IFormattable 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" 3386,tcImplicitConversionUsed,"This expression uses an implicit conversion to convert type '%s' to type '%s'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning." -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'." +3386,tcImplicitConversionUsed2,"This expression uses the implicit conversion '%s' to convert type '%s' to type '%s'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning." +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" #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/MethodCalls.fs b/src/fsharp/MethodCalls.fs index 3643a31ff47..b9edef9a7a3 100644 --- a/src/fsharp/MethodCalls.fs +++ b/src/fsharp/MethodCalls.fs @@ -218,13 +218,19 @@ let TryFindRelevantImplicitConversion (infoReader: InfoReader) ad reqdTy actualT | minfo :: _ -> Some (minfo, (reqdTy, reqdTy2, fun denv -> let reqdTy2Text, actualTyText, _cxs = NicePrint.minimalStringsOfTwoTypes denv reqdTy2 actualTy - errorR(Error(FSComp.SR.tcAmbiguousImplicitConversion(actualTyText, reqdTy2Text), m)))) + let implicitsText = NicePrint.multiLineStringOfMethInfos infoReader m denv implicits + errorR(Error(FSComp.SR.tcAmbiguousImplicitConversion(actualTyText, reqdTy2Text, implicitsText), m)))) | _ -> None else None else None +[] +type TypeDirectedConversion = + | BuiltIn + | Implicit of MethInfo + [] type TypeDirectedConversionUsed = | Yes of (DisplayEnv -> exn) @@ -243,9 +249,14 @@ let MapCombineTDC2D mapper xs ys = let rec AdjustRequiredTypeForTypeDirectedConversions (infoReader: InfoReader) ad isConstraint (reqdTy: TType) actualTy m = let g = infoReader.g - let warn denv = + let warn info denv = let reqdTyText, actualTyText, _cxs = NicePrint.minimalStringsOfTwoTypes denv reqdTy actualTy - Error(FSComp.SR.tcImplicitConversionUsed(actualTyText, reqdTyText), m) + match info with + | TypeDirectedConversion.BuiltIn -> + Error(FSComp.SR.tcImplicitConversionUsed(actualTyText, reqdTyText), m) + | TypeDirectedConversion.Implicit convMeth -> + let methText = NicePrint.stringOfMethInfo infoReader m denv convMeth + Error(FSComp.SR.tcImplicitConversionUsed2(methText, actualTyText, reqdTyText), m) if isConstraint then reqdTy, TypeDirectedConversionUsed.No, None @@ -262,17 +273,21 @@ let rec AdjustRequiredTypeForTypeDirectedConversions (infoReader: InfoReader) ad // 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), None + 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), None + 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), Some eqn + | Some (minfo, eqn) -> actualTy, TypeDirectedConversionUsed.Yes(warn (TypeDirectedConversion.Implicit minfo)), Some eqn | None -> reqdTy, TypeDirectedConversionUsed.No, None else reqdTy, TypeDirectedConversionUsed.No, None @@ -1204,6 +1219,10 @@ let rec AdjustExprForTypeDirectedConversions tcVal (g: TcGlobals) amap infoReade 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 diff --git a/src/fsharp/NicePrint.fs b/src/fsharp/NicePrint.fs index 4cf03cb77ec..6ec8c38b2dd 100755 --- a/src/fsharp/NicePrint.fs +++ b/src/fsharp/NicePrint.fs @@ -2214,7 +2214,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 fd7fc1cbd88..fece7c07232 100644 --- a/src/fsharp/NicePrint.fsi +++ b/src/fsharp/NicePrint.fsi @@ -58,7 +58,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/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index d0a4a987163..cd5c441f5a5 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -378,8 +378,8 @@ - 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'. - 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'. + 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} @@ -422,6 +422,11 @@ This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' Neshoda v interpolovaném řetězci. Interpolované řetězce nemůžou používat specifikátory formátu %, pokud se každému z nich nezadá nějaký výraz, např. %d{{1+1}}. diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index bd129dcab3c..2fef3d55b28 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -378,8 +378,8 @@ - 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'. - 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'. + 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} @@ -422,6 +422,11 @@ This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' Konflikt in interpolierter Zeichenfolge. Interpolierte Zeichenfolgen dürfen keine Formatbezeichner vom Typ "%" verwenden, es sei denn, jeder erhält einen Ausdruck, z. B. "%d{{1+1}}" diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index 94172c49822..93d774e5ab5 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -368,8 +368,8 @@ - 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'. - 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'. + 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} @@ -422,6 +422,11 @@ This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' La cadena interpolada no coincide. Las cadenas interpoladas no pueden usar los especificadores de formato "%", a menos que se les proporcione una expresión individualmente; por ejemplo, "%d{{1+1}}". diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index 9029b98de5e..63d4fae8448 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -368,8 +368,8 @@ - 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'. - 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'. + 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} @@ -422,6 +422,11 @@ This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' Incompatibilité dans la chaîne interpolée. Les chaînes interpolées ne peuvent pas utiliser les spécificateurs de format '%' à moins de recevoir une expression, par exemple '%d{{1+1}}' diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index 0c4cd6fea03..d13c9dd44e9 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -368,8 +368,8 @@ - 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'. - 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'. + 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} @@ -422,6 +422,11 @@ This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' Mancata corrispondenza nella stringa interpolata. Nelle stringhe interpolate non è possibile usare gli identificatori di formato '%' a meno che non si indichi un'espressione per ognuno di essi, ad esempio '%d{{1+1}}' diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index 653250970d6..41a0a3d231f 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -368,8 +368,8 @@ - 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'. - 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'. + 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} @@ -422,6 +422,11 @@ This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' 補間された文字列が一致しません。'%d{{1+1}}' などの式が指定されている場合を除き、補間された文字列では '%' 書式指定子を使用できません diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index 0fbdbb2a9a6..3cb8fb03c8e 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -368,8 +368,8 @@ - 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'. - 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'. + 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} @@ -422,6 +422,11 @@ This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' 보간 문자열의 불일치. 각 보간 문자열에 식(예: '%d{{1+1}}')이 지정되지 않는 한 '%' 형식 지정자를 사용할 수 없습니다. diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index ab5274e1e9c..e66085ca88d 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -368,8 +368,8 @@ - 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'. - 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'. + 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} @@ -422,6 +422,11 @@ This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' Niezgodność w interpolowanym ciągu. W interpolowanych ciągach nie można używać specyfikatorów formatu „%”, chyba że każdemu z nich odpowiada wyrażenie, na przykład „%d{{1+1}}”. diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index a3e8c17c143..6a0ba3db6d3 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -368,8 +368,8 @@ - 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'. - 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'. + 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} @@ -422,6 +422,11 @@ This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' Incompatibilidade na cadeia de caracteres interpolada. As cadeias de caracteres interpoladas não podem usar especificadores de formato '%', a menos que cada um receba uma expressão, por exemplo, '%d{{1+1}}' diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index 74829d26b0d..3b9f9d2a177 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -368,8 +368,8 @@ - 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'. - 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'. + 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} @@ -422,6 +422,11 @@ This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' Несоответствие в интерполированной строке. В интерполированных строках запрещено использовать описатели формата "%", если только каждому из них не назначено выражение, например "'%d{{1+1}}". diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index e6d11c8a091..39ed70db165 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -368,8 +368,8 @@ - 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'. - 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'. + 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} @@ -422,6 +422,11 @@ This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' Düz metin arasına kod eklenmiş dizede uyuşmazlık. Düz metin arasına kod eklenmiş dizeler, her birine '%d{{1+1}}' gibi bir ifade verilmedikçe '%' biçim belirticilerini kullanamaz diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index dd1f942cbe0..818946afa9c 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -368,8 +368,8 @@ - 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'. - 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'. + 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} @@ -422,6 +422,11 @@ This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' 在内插字符串中不匹配。内插字符串不会使用 "%" 格式说明符,除非为每个字符串提供像 "'%d{{1+1}}" 这样的表达式 diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index 98e1a87ca9f..e8d4d0e2a1f 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -368,8 +368,8 @@ - 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'. - 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'. + 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} @@ -422,6 +422,11 @@ This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + Mismatch in interpolated string. Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}' 插補字串不相符。除非每個插補字串都有一個運算式,否則不可使用 '%' 格式指定名稱,例如 '%d{{1+1}}' diff --git a/tests/fsharp/core/auto-widen/preview/test.bsl b/tests/fsharp/core/auto-widen/preview/test.bsl index a323bb59aa4..6da44724119 100644 --- a/tests/fsharp/core/auto-widen/preview/test.bsl +++ b/tests/fsharp/core/auto-widen/preview/test.bsl @@ -57,33 +57,33 @@ test.fsx(128,19,128,20): typecheck error FS3386: This expression uses an implici test.fsx(128,22,128,23): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'double'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(135,18,135,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(135,18,135,19): typecheck error FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:int -> C' to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. test.fsx(140,18,140,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(145,18,145,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'decimal'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(145,18,145,19): typecheck error FS3386: This expression uses the implicit conversion 'Decimal.op_Implicit(value: int) : decimal' to convert type 'int' to type 'decimal'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(147,18,147,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'decimal'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(147,18,147,19): typecheck error FS3386: This expression uses the implicit conversion 'Decimal.op_Implicit(value: int) : decimal' to convert type 'int' to type 'decimal'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(149,39,149,41): typecheck error FS3386: This expression uses an implicit conversion to convert type 'string' to type 'Xml.Linq.XNamespace'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(149,39,149,41): typecheck error FS3386: 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'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(154,18,154,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'string' to type 'Xml.Linq.XNamespace'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(154,18,154,20): typecheck error FS3386: 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'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(159,18,159,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'string' to type 'Xml.Linq.XName'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(159,18,159,21): typecheck error FS3386: 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'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(165,18,165,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(165,18,165,19): typecheck error FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:int -> C' to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(172,18,172,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'Y' to type 'X'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(172,18,172,21): typecheck error FS3386: This expression uses the implicit conversion 'static member Y.op_Implicit : y:Y -> X' to convert type 'Y' to type 'X'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(172,18,172,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'Y' to type 'X'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(172,18,172,21): typecheck error FS3386: This expression uses the implicit conversion 'static member Y.op_Implicit : y:Y -> X' to convert type 'Y' to type 'X'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(178,20,178,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(178,20,178,21): typecheck error FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:'T -> C<'T>' to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(180,15,180,16): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(180,15,180,16): typecheck error FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:'T -> C<'T>' to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(186,27,186,28): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'Nullable'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(186,27,186,28): typecheck error FS3386: This expression uses the implicit conversion 'Nullable.op_Implicit(value: int) : Nullable' to convert type 'int' to type 'Nullable'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(188,15,188,16): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'Nullable'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(188,15,188,16): typecheck error FS3386: This expression uses the implicit conversion 'Nullable.op_Implicit(value: int) : Nullable' to convert type 'int' to type 'Nullable'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. test.fsx(313,37,313,38): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. @@ -182,29 +182,33 @@ test.fsx(463,18,463,19): typecheck error FS0001: This expression was expected to but here has type 'int' -test.fsx(471,18,471,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(471,18,471,19): typecheck error FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:int -> C' to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. 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'. +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 FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(482,18,482,21): typecheck error FS3386: This expression uses the implicit conversion 'static member B.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -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'. +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 FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(482,18,482,21): typecheck error FS3386: This expression uses the implicit conversion 'static member B.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(507,18,507,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(507,18,507,21): typecheck error FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(507,18,507,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(507,18,507,21): typecheck error FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(519,18,519,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(519,18,519,21): typecheck error FS3386: This expression uses the implicit conversion 'static member B.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(519,18,519,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(519,18,519,21): typecheck error FS3386: This expression uses the implicit conversion 'static member B.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(538,18,538,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(538,18,538,21): typecheck error FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. -test.fsx(538,18,538,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(538,18,538,21): typecheck error FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. test.fsx(543,30,543,31): typecheck error FS0001: This expression was expected to have type 'float32' @@ -221,4 +225,4 @@ test.fsx(544,14,544,21): typecheck error FS0039: The type 'float64' is not defin float float`1 float32 - float32`1 \ No newline at end of file + float32`1 From 59e7d485e17b990394351b14683d9f2ac8127ec5 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Sun, 25 Jul 2021 00:44:52 +0100 Subject: [PATCH 36/42] update message --- src/fsharp/FSComp.txt | 2 +- src/fsharp/xlf/FSComp.txt.cs.xlf | 4 ++-- src/fsharp/xlf/FSComp.txt.de.xlf | 4 ++-- src/fsharp/xlf/FSComp.txt.es.xlf | 4 ++-- src/fsharp/xlf/FSComp.txt.fr.xlf | 4 ++-- src/fsharp/xlf/FSComp.txt.it.xlf | 4 ++-- src/fsharp/xlf/FSComp.txt.ja.xlf | 4 ++-- src/fsharp/xlf/FSComp.txt.ko.xlf | 4 ++-- src/fsharp/xlf/FSComp.txt.pl.xlf | 4 ++-- src/fsharp/xlf/FSComp.txt.pt-BR.xlf | 4 ++-- src/fsharp/xlf/FSComp.txt.ru.xlf | 4 ++-- src/fsharp/xlf/FSComp.txt.tr.xlf | 4 ++-- src/fsharp/xlf/FSComp.txt.zh-Hans.xlf | 4 ++-- src/fsharp/xlf/FSComp.txt.zh-Hant.xlf | 4 ++-- 14 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 7dd2e41e5e8..ac2ffafdbee 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1529,7 +1529,7 @@ featureNullableOptionalInterop,"nullable optional interop" featureDefaultInterfaceMemberConsumption,"default interface member consumption" featureStringInterpolation,"string interpolation" featureWitnessPassing,"witness passing for trait constraints in F# quotations" -featureAdditionalImplicitConversions,"implicit upcasts and other conversions for function returns, bindings and other expressions" +featureAdditionalImplicitConversions,"additional type-directed conversions" featureStructActivePattern,"struct representation for active patterns" 3353,fsiInvalidDirective,"Invalid directive '#%s %s'" 3360,typrelInterfaceWithConcreteAndVariable,"'%s' cannot implement the interface '%s' with the two instantiations '%s' and '%s' because they may unify." diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index e510d03ea9d..37db899464d 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -88,8 +88,8 @@ - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions + additional type-directed conversions + additional type-directed conversions diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index c86dd9c7820..5113d3ccc92 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -88,8 +88,8 @@ - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions + additional type-directed conversions + additional type-directed conversions diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index 4fadad93d1a..39293575b64 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -88,8 +88,8 @@ - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions + additional type-directed conversions + additional type-directed conversions diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index 759ac473dff..2a2e6065137 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -88,8 +88,8 @@ - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions + additional type-directed conversions + additional type-directed conversions diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index 7407050b0dc..7a518bafe75 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -88,8 +88,8 @@ - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions + additional type-directed conversions + additional type-directed conversions diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index 4e6c5112266..367d134f4ae 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -88,8 +88,8 @@ - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions + additional type-directed conversions + additional type-directed conversions diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index 6b8e78db54c..b973c054668 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -88,8 +88,8 @@ - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions + additional type-directed conversions + additional type-directed conversions diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index ce371178e39..a767efb704f 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -88,8 +88,8 @@ - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions + additional type-directed conversions + additional type-directed conversions diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index 68b2c9507cd..d317891e34f 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -88,8 +88,8 @@ - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions + additional type-directed conversions + additional type-directed conversions diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index 67c26f3bd9d..3c5c3fb3855 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -88,8 +88,8 @@ - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions + additional type-directed conversions + additional type-directed conversions diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index 5d972ae324b..aee8ed31743 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -88,8 +88,8 @@ - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions + additional type-directed conversions + additional type-directed conversions diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index bfc2e3b06f8..64ab3c73d22 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -88,8 +88,8 @@ - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions + additional type-directed conversions + additional type-directed conversions diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index 336c66c4924..0dc028d2458 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -88,8 +88,8 @@ - implicit upcasts and other conversions for function returns, bindings and other expressions - implicit upcasts and other conversions for function returns, bindings and other expressions + additional type-directed conversions + additional type-directed conversions From ba289f116afcaec0a7e4d9d797eb7f5feeb18814 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 26 Jul 2021 15:34:56 +0100 Subject: [PATCH 37/42] adjust mechanism and policy for warnings --- src/fsharp/CheckExpressions.fs | 3 +- src/fsharp/CompilerDiagnostics.fs | 4 +- src/fsharp/FSComp.txt | 6 +- src/fsharp/MethodCalls.fs | 7 +- src/fsharp/fsc/fsc.fsproj | 1 + src/fsharp/xlf/FSComp.txt.cs.xlf | 22 +- src/fsharp/xlf/FSComp.txt.de.xlf | 22 +- src/fsharp/xlf/FSComp.txt.es.xlf | 22 +- src/fsharp/xlf/FSComp.txt.fr.xlf | 22 +- src/fsharp/xlf/FSComp.txt.it.xlf | 22 +- src/fsharp/xlf/FSComp.txt.ja.xlf | 22 +- src/fsharp/xlf/FSComp.txt.ko.xlf | 22 +- src/fsharp/xlf/FSComp.txt.pl.xlf | 22 +- src/fsharp/xlf/FSComp.txt.pt-BR.xlf | 22 +- src/fsharp/xlf/FSComp.txt.ru.xlf | 22 +- src/fsharp/xlf/FSComp.txt.tr.xlf | 22 +- src/fsharp/xlf/FSComp.txt.zh-Hans.xlf | 22 +- src/fsharp/xlf/FSComp.txt.zh-Hant.xlf | 22 +- tests/fsharp/core/auto-widen/preview/test.bsl | 608 +++++++++++++++--- tests/fsharp/tests.fs | 2 +- 20 files changed, 734 insertions(+), 183 deletions(-) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 61e9b8ffa2e..23b299bd626 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -479,7 +479,8 @@ let UnifyOverallType cenv (env: TcEnv) m overallTy actualTy = | 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 diff --git a/src/fsharp/CompilerDiagnostics.fs b/src/fsharp/CompilerDiagnostics.fs index 4aac15b7880..d6a427b5b89 100644 --- a/src/fsharp/CompilerDiagnostics.fs +++ b/src/fsharp/CompilerDiagnostics.fs @@ -374,8 +374,10 @@ let warningOn err level specificWarnOn = match n with | 1182 -> false // chkUnusedValue - off by default | 3180 -> false // abImplicitHeapAllocation - off by default - | 3386 -> false // tcImplicitConversionUsed - off by default | 3517 -> false // optFailedToInlineSuggestedValue - off by default + | 3388 -> false // tcSubsumptionImplicitConversionUsed - off by default + | 3389 -> false // tcBuiltInImplicitConversionUsed - off by default + | 3390 -> false // tcLibDefinedImplicitConversionUsed - off by default | _ -> level >= GetWarningLevel err let SplitRelatedDiagnostics(err: PhasedDiagnostic) : PhasedDiagnostic * PhasedDiagnostic list = diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index ac2ffafdbee..79370e1ee31 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1557,9 +1557,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" -3386,tcImplicitConversionUsed,"This expression uses an implicit conversion to convert type '%s' to type '%s'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning." -3386,tcImplicitConversionUsed2,"This expression uses the implicit conversion '%s' to convert type '%s' to type '%s'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning." 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,tcLibDefinedImplicitConversionUsed,"This expression uses the implicit conversion '%s' to convert type '%s' to type '%s'." +3391,tcFSharpDefinedImplicitConversionUsed,"This expression uses the F#-defined implicit conversion '%s' to convert type '%s' to type '%s'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\"." #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/MethodCalls.fs b/src/fsharp/MethodCalls.fs index f21433a2609..38c3a5105f5 100644 --- a/src/fsharp/MethodCalls.fs +++ b/src/fsharp/MethodCalls.fs @@ -251,10 +251,13 @@ let rec AdjustRequiredTypeForTypeDirectedConversions (infoReader: InfoReader) ad let reqdTyText, actualTyText, _cxs = NicePrint.minimalStringsOfTwoTypes denv reqdTy actualTy match info with | TypeDirectedConversion.BuiltIn -> - Error(FSComp.SR.tcImplicitConversionUsed(actualTyText, reqdTyText), m) + Error(FSComp.SR.tcBuiltInImplicitConversionUsed(actualTyText, reqdTyText), m) | TypeDirectedConversion.Implicit convMeth -> let methText = NicePrint.stringOfMethInfo infoReader m denv convMeth - Error(FSComp.SR.tcImplicitConversionUsed2(methText, actualTyText, reqdTyText), m) + if convMeth.IsILMethod then + Error(FSComp.SR.tcLibDefinedImplicitConversionUsed(methText, actualTyText, reqdTyText), m) + else + Error(FSComp.SR.tcFSharpDefinedImplicitConversionUsed(methText, actualTyText, reqdTyText), m) if isConstraint then reqdTy, TypeDirectedConversionUsed.No, None diff --git a/src/fsharp/fsc/fsc.fsproj b/src/fsharp/fsc/fsc.fsproj index 7fa31fc2151..2c83e28ccc2 100644 --- a/src/fsharp/fsc/fsc.fsproj +++ b/src/fsharp/fsc/fsc.fsproj @@ -10,6 +10,7 @@ $(NoWarn);44;45;55;62;75;1204 true $(OtherFlags) --maxerrors:20 --extraoptimizationloops:1 + $(OtherFlags) --langversion:preview true true diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index 37db899464d..28357b86f3f 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -487,19 +487,24 @@ Atributy nejde použít pro rozšíření typů. + + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + + Byref types are not allowed in an open type declaration. Typy Byref nejsou v deklaraci otevřeného typu povolené. - - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. @@ -582,6 +587,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} diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index 5113d3ccc92..a8c8a8e7220 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -487,19 +487,24 @@ Attribute können nicht auf Typerweiterungen angewendet werden. + + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + + Byref types are not allowed in an open type declaration. Byref-Typen sind in einer Deklaration für offene Typen nicht zulässig. - - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. @@ -582,6 +587,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} diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index 39293575b64..b4822c4cfb0 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -487,19 +487,24 @@ Los atributos no se pueden aplicar a las extensiones de tipo. + + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + + Byref types are not allowed in an open type declaration. No se permiten tipos byref en una declaración de tipo abierto. - - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. @@ -582,6 +587,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} diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index 2a2e6065137..1a3d50a1ce9 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -487,19 +487,24 @@ Impossible d'appliquer des attributs aux extensions de type. + + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + + Byref types are not allowed in an open type declaration. Les types Byref ne sont pas autorisés dans une déclaration de type ouverte. - - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. @@ -582,6 +587,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} diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index 7a518bafe75..44842a09f57 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -487,19 +487,24 @@ Gli attributi non possono essere applicati a estensioni di tipo. + + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + + Byref types are not allowed in an open type declaration. I tipi byref non sono consentiti in una dichiarazione di tipo aperto. - - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. @@ -582,6 +587,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} diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index 367d134f4ae..2f6a989b8cd 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -487,19 +487,24 @@ 属性を型拡張に適用することはできません。 + + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + + Byref types are not allowed in an open type declaration. Byref 型は、オープン型宣言では使用できません。 - - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. @@ -582,6 +587,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} diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index b973c054668..b0b6f3e5a1b 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -487,19 +487,24 @@ 형식 확장에 특성을 적용할 수 없습니다. + + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + + Byref types are not allowed in an open type declaration. Byref 형식은 개방형 형식 선언에서 허용되지 않습니다. - - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. @@ -582,6 +587,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} diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index a767efb704f..635455fe3d7 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -487,19 +487,24 @@ Atrybutów nie można stosować do rozszerzeń typu. + + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + + Byref types are not allowed in an open type declaration. Typy ByRef są niedozwolone w deklaracji typu otwartego. - - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. @@ -582,6 +587,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} diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index d317891e34f..e8f797ed3d1 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -487,19 +487,24 @@ Os atributos não podem ser aplicados às extensões de tipo. + + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + + Byref types are not allowed in an open type declaration. Os tipos Byref não são permitidos em uma declaração de tipo aberto. - - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. @@ -582,6 +587,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} diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index 3c5c3fb3855..5a944c33961 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -487,19 +487,24 @@ Атрибуты не могут быть применены к расширениям типа. + + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + + Byref types are not allowed in an open type declaration. Типы ByRef запрещены в объявлении открытого типа. - - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. @@ -582,6 +587,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} diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index aee8ed31743..5d78577f6d6 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -487,19 +487,24 @@ Öznitelikler tür uzantılarına uygulanamaz. + + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + + Byref types are not allowed in an open type declaration. Açık tür bildiriminde Byref türlerine izin verilmez. - - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. @@ -582,6 +587,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} diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index 64ab3c73d22..1daac41fdc1 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -487,19 +487,24 @@ 属性不可应用于类型扩展。 + + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + + Byref types are not allowed in an open type declaration. 在开放类型声明中不允许使用 Byref 类型。 - - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. @@ -582,6 +587,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} diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index 0dc028d2458..303f47e5960 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -487,19 +487,24 @@ 屬性無法套用到類型延伸模組。 + + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". + + Byref types are not allowed in an open type declaration. 開放式類型宣告中不允許 Byref 類型。 - - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses an implicit conversion to convert type '{0}' to type '{1}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. - This expression uses the implicit conversion '{0}' to convert type '{1}' to type '{2}'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. + + 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}'. @@ -582,6 +587,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} diff --git a/tests/fsharp/core/auto-widen/preview/test.bsl b/tests/fsharp/core/auto-widen/preview/test.bsl index 6da44724119..eed98877bd2 100644 --- a/tests/fsharp/core/auto-widen/preview/test.bsl +++ b/tests/fsharp/core/auto-widen/preview/test.bsl @@ -1,188 +1,600 @@ -test.fsx(58,22,58,24): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(59,22,59,23): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(60,28,60,29): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(60,30,60,31): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(60,32,60,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(60,34,60,35): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(61,28,61,29): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(61,30,61,31): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(61,32,61,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'float'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(63,22,63,43): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(64,28,64,49): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(64,50,64,71): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(68,22,68,25): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(68,22,68,25): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(69,26,69,29): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(69,26,69,29): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(93,18,93,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(93,18,93,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(99,20,99,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(99,20,99,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(116,20,116,21): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(121,19,121,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(121,19,121,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(122,19,122,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(122,22,122,23): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(127,19,127,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'double'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(127,19,127,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'double'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(128,19,128,20): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'double'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(128,22,128,23): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'double'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(135,18,135,19): typecheck error FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:int -> C' to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(140,18,140,19): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(145,18,145,19): typecheck error FS3386: This expression uses the implicit conversion 'Decimal.op_Implicit(value: int) : decimal' to convert type 'int' to type 'decimal'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(147,18,147,19): typecheck error FS3386: This expression uses the implicit conversion 'Decimal.op_Implicit(value: int) : decimal' to convert type 'int' to type 'decimal'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(149,39,149,41): typecheck error FS3386: 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'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(154,18,154,20): typecheck error FS3386: 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'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(159,18,159,21): typecheck error FS3386: 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'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(165,18,165,19): typecheck error FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:int -> C' to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(172,18,172,21): typecheck error FS3386: This expression uses the implicit conversion 'static member Y.op_Implicit : y:Y -> X' to convert type 'Y' to type 'X'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(172,18,172,21): typecheck error FS3386: This expression uses the implicit conversion 'static member Y.op_Implicit : y:Y -> X' to convert type 'Y' to type 'X'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(178,20,178,21): typecheck error FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:'T -> C<'T>' to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(180,15,180,16): typecheck error FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:'T -> C<'T>' to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(186,27,186,28): typecheck error FS3386: This expression uses the implicit conversion 'Nullable.op_Implicit(value: int) : Nullable' to convert type 'int' to type 'Nullable'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(188,15,188,16): typecheck error FS3386: This expression uses the implicit conversion 'Nullable.op_Implicit(value: int) : Nullable' to convert type 'int' to type 'Nullable'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(313,37,313,38): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(314,37,314,38): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(317,50,317,51): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(319,52,319,53): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(320,37,320,38): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(323,57,323,58): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(325,57,325,58): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(326,37,326,38): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(328,42,328,43): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(330,42,330,43): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(331,38,331,39): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(335,36,335,37): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(337,17,337,18): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(341,30,341,31): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(344,32,344,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(346,17,346,18): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(351,37,351,38): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(354,37,354,38): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(356,17,356,18): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(359,21,359,22): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(362,21,362,22): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(364,17,364,18): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(368,39,368,40): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(369,39,369,40): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(372,52,372,53): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(135,18,135,19): typecheck error FS3391: This expression uses the F#-defined implicit conversion 'static member C.op_Implicit : x:int -> C' to convert type 'int' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3389". -test.fsx(374,54,374,55): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(375,39,375,40): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(378,59,378,60): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(380,59,380,60): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(381,39,381,40): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(383,44,383,45): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(147,18,147,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(385,44,385,45): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(386,40,386,41): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(149,39,149,41): 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(390,37,390,38): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(391,39,391,40): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(394,52,394,53): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(396,54,396,55): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(397,39,397,40): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(400,59,400,60): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(165,18,165,19): typecheck error FS3391: This expression uses the F#-defined implicit conversion 'static member C.op_Implicit : x:int -> C' to convert type 'int' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3389". -test.fsx(402,59,402,60): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(403,39,403,40): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(172,18,172,21): typecheck error FS3391: This expression uses the F#-defined 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 "3389". -test.fsx(405,44,405,45): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(172,18,172,21): typecheck error FS3391: This expression uses the F#-defined 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 "3389". -test.fsx(407,44,407,45): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(178,20,178,21): typecheck error FS3391: This expression uses the F#-defined 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 "3389". -test.fsx(408,40,408,41): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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(452,32,452,33): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(180,15,180,16): typecheck error FS3391: This expression uses the F#-defined 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 "3389". -test.fsx(454,46,454,47): typecheck error FS3386: This expression uses an implicit conversion to convert type 'int' to type 'int64'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +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 FS3390: This expression uses the implicit conversion 'Nullable.op_Implicit(value: int) : Nullable' to convert type 'int' to type 'Nullable'. + +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 FS3390: This expression uses the implicit conversion 'Nullable.op_Implicit(value: int) : Nullable' to convert type 'int' to type 'Nullable'. + +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 FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:int -> C' to convert type 'int' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(471,18,471,19): typecheck error FS3391: This expression uses the F#-defined implicit conversion 'static member C.op_Implicit : x:int -> C' to convert type 'int' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3389". + +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 @@ -190,25 +602,25 @@ test.fsx(482,18,482,21): typecheck error FS3387: This expression has type 'B' an static member B.op_Implicit : x:B -> C static member C.op_Implicit : x:B -> C -test.fsx(482,18,482,21): typecheck error FS3386: This expression uses the implicit conversion 'static member B.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(482,18,482,21): typecheck error FS3391: This expression uses the F#-defined 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 "3389". 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 FS3386: This expression uses the implicit conversion 'static member B.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(482,18,482,21): typecheck error FS3391: This expression uses the F#-defined 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 "3389". -test.fsx(507,18,507,21): typecheck error FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(507,18,507,21): typecheck error FS3391: This expression uses the F#-defined 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 "3389". -test.fsx(507,18,507,21): typecheck error FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(507,18,507,21): typecheck error FS3391: This expression uses the F#-defined 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 "3389". -test.fsx(519,18,519,21): typecheck error FS3386: This expression uses the implicit conversion 'static member B.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(519,18,519,21): typecheck error FS3391: This expression uses the F#-defined 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 "3389". -test.fsx(519,18,519,21): typecheck error FS3386: This expression uses the implicit conversion 'static member B.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(519,18,519,21): typecheck error FS3391: This expression uses the F#-defined 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 "3389". -test.fsx(538,18,538,21): typecheck error FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(538,18,538,21): typecheck error FS3391: This expression uses the F#-defined 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 "3389". -test.fsx(538,18,538,21): typecheck error FS3386: This expression uses the implicit conversion 'static member C.op_Implicit : x:B -> C' to convert type 'B' to type 'C'. Warnings are enabled for implicit conversions. Consider using an explicit conversion or disabling this warning. +test.fsx(538,18,538,21): typecheck error FS3391: This expression uses the F#-defined 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 "3389". test.fsx(543,30,543,31): typecheck error FS0001: This expression was expected to have type 'float32' diff --git a/tests/fsharp/tests.fs b/tests/fsharp/tests.fs index 9d54e65bf30..d88a3a9577f 100644 --- a/tests/fsharp/tests.fs +++ b/tests/fsharp/tests.fs @@ -83,7 +83,7 @@ module CoreTests = [] let ``auto-widen-version-preview-warns-on``() = let cfg = testConfig "core/auto-widen/preview" - let cfg = { cfg with fsc_flags = cfg.fsc_flags + " --warnon:3386 --warnaserror+ --define:NEGATIVE" } + let cfg = { cfg with fsc_flags = cfg.fsc_flags + " --warnon:3388 --warnon:3389 --warnon:3390 --warnaserror+ --define:NEGATIVE" } singleVersionedNegTest cfg "preview" "test" [] From 8a300602b0bb1a15057770c572e81097ab89a027 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 26 Jul 2021 23:48:09 +0100 Subject: [PATCH 38/42] adjust warnings implementation and policy --- src/fsharp/CheckExpressions.fs | 32 +- src/fsharp/CompilerDiagnostics.fs | 2 +- src/fsharp/ConstraintSolver.fs | 24 +- src/fsharp/ConstraintSolver.fsi | 2 +- src/fsharp/FSComp.txt | 4 +- src/fsharp/MethodCalls.fs | 14 +- src/fsharp/MethodCalls.fsi | 3 +- src/fsharp/fsc/fsc.fsproj | 1 - src/fsharp/fscmain.fs | 2 +- src/fsharp/xlf/FSComp.txt.cs.xlf | 12 +- src/fsharp/xlf/FSComp.txt.de.xlf | 12 +- src/fsharp/xlf/FSComp.txt.es.xlf | 12 +- src/fsharp/xlf/FSComp.txt.fr.xlf | 12 +- src/fsharp/xlf/FSComp.txt.it.xlf | 12 +- src/fsharp/xlf/FSComp.txt.ja.xlf | 12 +- src/fsharp/xlf/FSComp.txt.ko.xlf | 12 +- src/fsharp/xlf/FSComp.txt.pl.xlf | 12 +- src/fsharp/xlf/FSComp.txt.pt-BR.xlf | 12 +- src/fsharp/xlf/FSComp.txt.ru.xlf | 12 +- src/fsharp/xlf/FSComp.txt.tr.xlf | 12 +- src/fsharp/xlf/FSComp.txt.zh-Hans.xlf | 12 +- src/fsharp/xlf/FSComp.txt.zh-Hant.xlf | 12 +- .../auto-widen/preview-default-warns/test.bsl | 69 +++ .../auto-widen/preview-default-warns/test.fsx | 574 ++++++++++++++++++ tests/fsharp/core/auto-widen/preview/test.bsl | 38 +- tests/fsharp/tests.fs | 6 + 26 files changed, 788 insertions(+), 139 deletions(-) create mode 100644 tests/fsharp/core/auto-widen/preview-default-warns/test.bsl create mode 100644 tests/fsharp/core/auto-widen/preview-default-warns/test.fsx diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 23b299bd626..9f4f02d5b24 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -462,14 +462,14 @@ let UnifyTypes cenv (env: TcEnv) m actualTy expectedTy = // to actually build the expression for any conversion applied. let UnifyOverallType cenv (env: TcEnv) m overallTy actualTy = match overallTy with - | MustConvertTo(reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions -> + | 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 false reqdTy actualTy m + 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 @@ -5335,14 +5335,14 @@ and TcExprFlex cenv flex compat (desiredTy: TType) (env: TcEnv) tpenv (synExpr: if compat then (destTyparTy cenv.g argty).SetIsCompatFlex(true) AddCxTypeMustSubsumeType ContextInfo.NoContext env.DisplayEnv cenv.css synExpr.Range NoTrace desiredTy argty - let expr2, tpenv = TcExprFlex2 cenv argty env tpenv synExpr + let expr2, tpenv = TcExprFlex2 cenv argty env false tpenv synExpr let expr3 = mkCoerceIfNeeded cenv.g desiredTy argty expr2 expr3, tpenv else - TcExprFlex2 cenv desiredTy env tpenv synExpr + TcExprFlex2 cenv desiredTy env false tpenv synExpr -and TcExprFlex2 cenv desiredTy env tpenv synExpr = - TcExpr cenv (MustConvertTo desiredTy) env 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 @@ -5510,12 +5510,12 @@ and TcExprUndelayedNoType cenv env tpenv synExpr: Expr * TType * _ = /// and TcPropagatingExprLeafThenConvert cenv overallTy actualTy (env: TcEnv) (* canAdhoc *) m (f: unit -> Expr * UnscopedTyparEnv) = match overallTy with - | MustConvertTo(reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions -> + | 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 (MustConvertTo reqdTy) actualTy + UnifyOverallType cenv env m overallTy actualTy // Process the construct let expr, tpenv = f () // Build the conversion @@ -5539,7 +5539,7 @@ and TcPropagatingExprLeafThenConvert cenv overallTy actualTy (env: TcEnv) (* can /// - 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) -> + | 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. @@ -5567,7 +5567,7 @@ and TcNonPropagatingExprLeafThenConvert cenv (overallTy: OverallTy) (env: TcEnv) and TcAdjustExprForTypeDirectedConversions cenv (overallTy: OverallTy) actualTy (env: TcEnv) (* canAdhoc *) m expr = match overallTy with - | MustConvertTo(reqdTy) when cenv.g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions -> + | 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 | _ -> @@ -5627,7 +5627,7 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = 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 (MustConvertTo 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 @@ -5641,7 +5641,7 @@ and TcExprUndelayed cenv (overallTy: OverallTy) env tpenv (synExpr: SynExpr) = | SynExpr.Typed (synBodyExpr, synType, m) -> let tgtTy, tpenv = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synType UnifyOverallType cenv env m overallTy tgtTy - let bodyExpr, tpenv = TcExpr cenv (MustConvertTo tgtTy) env tpenv synBodyExpr + let bodyExpr, tpenv = TcExpr cenv (MustConvertTo (false, tgtTy)) env tpenv synBodyExpr let bodyExpr2 = TcAdjustExprForTypeDirectedConversions cenv overallTy tgtTy env (* true *) m bodyExpr bodyExpr2, tpenv @@ -6047,7 +6047,7 @@ and TcIteratedLambdas cenv isFirst (env: TcEnv) overallTy takenNames tpenv e = { envinner with eLambdaArgInfos = rest } | [] -> envinner - let bodyExpr, tpenv = TcIteratedLambdas cenv false envinner (MustConvertTo 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))) @@ -7732,7 +7732,7 @@ and TcFunctionApplicationThen cenv (overallTy: OverallTy) env tpenv mExprAndArg | _ -> false) | _ -> () - let arg, tpenv = TcExprFlex2 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 @@ -9242,7 +9242,7 @@ and TcMethodArg cenv env (lambdaPropagationInfo, tpenv) (lambdaPropagationInfoFo | _ -> () loop argTy 0 - let e', tpenv = TcExprFlex2 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. // @@ -9675,7 +9675,7 @@ and TcNormalizedBinding declKind (cenv: cenv) env tpenv overallTy safeThisValOpt let envinner = { envinner with eLambdaArgInfos = argInfos } if isCtor then TcExprThatIsCtorBody (safeThisValOpt, safeInitInfo) cenv (MustEqual overallExprTy) envinner tpenv rhsExpr - else TcExprThatCantBeCtorBody cenv (MustConvertTo 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 diff --git a/src/fsharp/CompilerDiagnostics.fs b/src/fsharp/CompilerDiagnostics.fs index d6a427b5b89..8ce2fe9e148 100644 --- a/src/fsharp/CompilerDiagnostics.fs +++ b/src/fsharp/CompilerDiagnostics.fs @@ -377,7 +377,7 @@ let warningOn err level specificWarnOn = | 3517 -> false // optFailedToInlineSuggestedValue - off by default | 3388 -> false // tcSubsumptionImplicitConversionUsed - off by default | 3389 -> false // tcBuiltInImplicitConversionUsed - off by default - | 3390 -> false // tcLibDefinedImplicitConversionUsed - 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 a829ec89ffc..74336feb445 100644 --- a/src/fsharp/ConstraintSolver.fs +++ b/src/fsharp/ConstraintSolver.fs @@ -212,13 +212,13 @@ type OverallTy = | MustEqual of TType /// Each branch of the expression must convert to the type indicated - | MustConvertTo of ty: TType + | 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 + | MustConvertTo (_, ty) -> ty exception ConstraintSolverTupleDiffLengths of displayEnv: DisplayEnv * TType list * TType list * range * range @@ -2354,7 +2354,7 @@ and CanMemberSigsMatchUpToCheck match reqdRetTyOpt with | Some _ when ( (* minfo.IsConstructor || *) not alwaysCheckReturn && isNil unnamedCalledOutArgs) -> ResultD TypeDirectedConversionUsed.No - | Some (MustConvertTo(reqdTy)) when g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions -> + | Some (MustConvertTo(_, reqdTy)) when g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions -> let methodRetTy = calledMeth.CalledReturnTypeAfterOutArgTupling subsumeOrConvertTypes reqdTy methodRetTy | Some reqdRetTy -> @@ -2464,9 +2464,9 @@ and TypesMustSubsume (csenv: ConstraintSolverEnv) ndeep trace cxsln m calledArgT return TypeDirectedConversionUsed.No } -and TypesMustSubsumeOrConvert (csenv: ConstraintSolverEnv) ad ndeep trace cxsln isConstraint m reqdTy actualTy = +and ReturnTypesMustSubsumeOrConvert (csenv: ConstraintSolverEnv) ad ndeep trace cxsln isConstraint m reqdTy actualTy = trackErrors { - let reqdTy, usesTDC, eqn = AdjustRequiredTypeForTypeDirectedConversions csenv.InfoReader ad isConstraint reqdTy actualTy m + 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 @@ -2674,7 +2674,7 @@ and ResolveOverloading alwaysCheckReturn (TypesEquiv csenv ndeep (WithTrace newTrace) cxsln) // instantiations equivalent (TypesMustSubsume csenv ndeep (WithTrace newTrace) cxsln m) // obj can subsume - (TypesMustSubsumeOrConvert csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome m) // return can subsume or convert + (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) @@ -2695,7 +2695,7 @@ and ResolveOverloading alwaysCheckReturn (TypesEquiv csenv ndeep (WithTrace newTrace) cxsln) // instantiations equivalent (TypesMustSubsume csenv ndeep (WithTrace newTrace) cxsln m) // obj can subsume - (TypesMustSubsumeOrConvert csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome m) // return can subsume or convert + (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) @@ -2732,7 +2732,7 @@ and ResolveOverloading alwaysCheckReturn (TypesEquiv csenv ndeep (WithTrace newTrace) cxsln) (TypesMustSubsume csenv ndeep (WithTrace newTrace) cxsln m) - (TypesMustSubsumeOrConvert csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome m) + (ReturnTypesMustSubsumeOrConvert csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome m) (ArgsMustSubsumeOrConvertWithContextualReport csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome calledMeth) reqdRetTyOpt calledMeth) with @@ -2961,7 +2961,7 @@ and ResolveOverloading true (TypesEquiv csenv ndeep trace cxsln) // instantiations equal (TypesMustSubsume csenv ndeep trace cxsln m) // obj can subsume - (TypesMustSubsumeOrConvert csenv ad ndeep trace cxsln cx.IsSome m) // return can subsume or convert + (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 @@ -2980,8 +2980,8 @@ and ResolveOverloading return! ErrorD(Error(FSComp.SR.tcByrefReturnImplicitlyDereferenced(), m)) else match reqdRetTy with - | MustConvertTo(reqdRetTy) when g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions -> - let! _usesTDC = TypesMustSubsumeOrConvert csenv ad ndeep trace cxsln true m reqdRetTy actualRetTy + | 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 @@ -3022,7 +3022,7 @@ let UnifyUniqueOverloading true // always check return type (TypesEquiv csenv ndeep NoTrace None) (TypesMustSubsume csenv ndeep NoTrace None m) - (TypesMustSubsumeOrConvert csenv ad ndeep NoTrace None false m) + (ReturnTypesMustSubsumeOrConvert csenv ad ndeep NoTrace None false m) (ArgsMustSubsumeOrConvert csenv ad ndeep NoTrace None false false) (Some reqdRetTy) calledMeth diff --git a/src/fsharp/ConstraintSolver.fsi b/src/fsharp/ConstraintSolver.fsi index ab899fa3550..fb0d76a2b4e 100644 --- a/src/fsharp/ConstraintSolver.fsi +++ b/src/fsharp/ConstraintSolver.fsi @@ -112,7 +112,7 @@ type OverallTy = | MustEqual of TType /// Each branch of the expression must convert to the type indicated - | MustConvertTo of ty: TType + | MustConvertTo of isMethodArg: bool * ty: TType /// Represents a point where no subsumption/widening is possible member Commit: TType diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 79370e1ee31..31a3d4d521b 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1560,8 +1560,8 @@ forFormatInvalidForInterpolated4,"Interpolated strings used as type IFormattable 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,tcLibDefinedImplicitConversionUsed,"This expression uses the implicit conversion '%s' to convert type '%s' to type '%s'." -3391,tcFSharpDefinedImplicitConversionUsed,"This expression uses the F#-defined implicit conversion '%s' to convert type '%s' to type '%s'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\"." +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/MethodCalls.fs b/src/fsharp/MethodCalls.fs index 38c3a5105f5..7507dcc2797 100644 --- a/src/fsharp/MethodCalls.fs +++ b/src/fsharp/MethodCalls.fs @@ -244,7 +244,7 @@ let MapCombineTDCD mapper xs = let MapCombineTDC2D mapper xs ys = MapReduce2D mapper TypeDirectedConversionUsed.No TypeDirectedConversionUsed.Combine xs ys -let rec AdjustRequiredTypeForTypeDirectedConversions (infoReader: InfoReader) ad isConstraint (reqdTy: TType) actualTy m = +let rec AdjustRequiredTypeForTypeDirectedConversions (infoReader: InfoReader) ad isMethodArg isConstraint (reqdTy: TType) actualTy m = let g = infoReader.g let warn info denv = @@ -254,10 +254,10 @@ let rec AdjustRequiredTypeForTypeDirectedConversions (infoReader: InfoReader) ad Error(FSComp.SR.tcBuiltInImplicitConversionUsed(actualTyText, reqdTyText), m) | TypeDirectedConversion.Implicit convMeth -> let methText = NicePrint.stringOfMethInfo infoReader m denv convMeth - if convMeth.IsILMethod then - Error(FSComp.SR.tcLibDefinedImplicitConversionUsed(methText, actualTyText, reqdTyText), m) + if isMethodArg then + Error(FSComp.SR.tcImplicitConversionUsedForMethodArg(methText, actualTyText, reqdTyText), m) else - Error(FSComp.SR.tcFSharpDefinedImplicitConversionUsed(methText, actualTyText, reqdTyText), m) + Error(FSComp.SR.tcImplicitConversionUsedForNonMethodArg(methText, actualTyText, reqdTyText), m) if isConstraint then reqdTy, TypeDirectedConversionUsed.No, None @@ -270,7 +270,7 @@ let rec AdjustRequiredTypeForTypeDirectedConversions (infoReader: InfoReader) ad // (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 isConstraint delegateTy actualTy m + 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 @@ -302,7 +302,7 @@ let AdjustCalledArgTypeForTypeDirectedConversionsAndAutoQuote (infoReader: InfoR if calledArg.ReflArgInfo.AutoQuote && isQuotedExprTy g calledArgTy && not (isQuotedExprTy g callerArgTy) then destQuotedExprTy g calledArgTy, TypeDirectedConversionUsed.No, None else - AdjustRequiredTypeForTypeDirectedConversions infoReader ad false calledArgTy callerArgTy m + 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 (infoReader: InfoReader) ad enforceNullableOptionalsKnownTypes (calledArg: CalledArg) calledArgTy (callerArg: CallerArg<_>) = @@ -348,7 +348,7 @@ let AdjustCalledArgTypeForOptionals (infoReader: InfoReader) ad enforceNullableO // If inference has worked out it's a struct (e.g. an int) then use this elif isStructTy g callerArgTy then let calledArgTy2 = destNullableTy g calledArgTy - AdjustRequiredTypeForTypeDirectedConversions infoReader ad false calledArgTy2 callerArgTy m + 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 diff --git a/src/fsharp/MethodCalls.fsi b/src/fsharp/MethodCalls.fsi index 5d97857d3f5..1624d0d9662 100644 --- a/src/fsharp/MethodCalls.fsi +++ b/src/fsharp/MethodCalls.fsi @@ -124,7 +124,8 @@ val MapCombineTDC2D: mapper:('a -> 'b -> OperationResult ad: AccessorDomain -> - isConstraint:bool -> + isMethodArg: bool -> + isConstraint: bool -> reqdTy: TType -> actualTy:TType -> m: range diff --git a/src/fsharp/fsc/fsc.fsproj b/src/fsharp/fsc/fsc.fsproj index 2c83e28ccc2..7fa31fc2151 100644 --- a/src/fsharp/fsc/fsc.fsproj +++ b/src/fsharp/fsc/fsc.fsproj @@ -10,7 +10,6 @@ $(NoWarn);44;45;55;62;75;1204 true $(OtherFlags) --maxerrors:20 --extraoptimizationloops:1 - $(OtherFlags) --langversion:preview true true 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 28357b86f3f..01f3649a721 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -487,11 +487,6 @@ Atributy nejde použít pro rozšíření typů. - - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - - Byref types are not allowed in an open type declaration. Typy Byref nejsou v deklaraci otevřeného typu povolené. @@ -502,11 +497,16 @@ 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#. diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index a8c8a8e7220..775a2c4cf14 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -487,11 +487,6 @@ Attribute können nicht auf Typerweiterungen angewendet werden. - - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - - Byref types are not allowed in an open type declaration. Byref-Typen sind in einer Deklaration für offene Typen nicht zulässig. @@ -502,11 +497,16 @@ 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. diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index b4822c4cfb0..0b6f20a0f6c 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -487,11 +487,6 @@ Los atributos no se pueden aplicar a las extensiones de tipo. - - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - - Byref types are not allowed in an open type declaration. No se permiten tipos byref en una declaración de tipo abierto. @@ -502,11 +497,16 @@ 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#. diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index 1a3d50a1ce9..2807f6d07a7 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -487,11 +487,6 @@ Impossible d'appliquer des attributs aux extensions de type. - - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - - Byref types are not allowed in an open type declaration. Les types Byref ne sont pas autorisés dans une déclaration de type ouverte. @@ -502,11 +497,16 @@ 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#. diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index 44842a09f57..4c38385f04d 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -487,11 +487,6 @@ Gli attributi non possono essere applicati a estensioni di tipo. - - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - - Byref types are not allowed in an open type declaration. I tipi byref non sono consentiti in una dichiarazione di tipo aperto. @@ -502,11 +497,16 @@ 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#. diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index 2f6a989b8cd..1996966dcc8 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -487,11 +487,6 @@ 属性を型拡張に適用することはできません。 - - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - - Byref types are not allowed in an open type declaration. Byref 型は、オープン型宣言では使用できません。 @@ -502,11 +497,16 @@ 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# デリゲート型であるメソッドのインライン関数のパラメーターに対してのみです。 diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index b0b6f3e5a1b..000fb0e0fef 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -487,11 +487,6 @@ 형식 확장에 특성을 적용할 수 없습니다. - - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - - Byref types are not allowed in an open type declaration. Byref 형식은 개방형 형식 선언에서 허용되지 않습니다. @@ -502,11 +497,16 @@ 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# 대리자 형식인 메서드의 인라인 함수 매개 변수에만 사용할 수 있습니다. diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index 635455fe3d7..ebb9b583e79 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -487,11 +487,6 @@ Atrybutów nie można stosować do rozszerzeń typu. - - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - - Byref types are not allowed in an open type declaration. Typy ByRef są niedozwolone w deklaracji typu otwartego. @@ -502,11 +497,16 @@ 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 #. diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index e8f797ed3d1..2a5d20c85fc 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -487,11 +487,6 @@ Os atributos não podem ser aplicados às extensões de tipo. - - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - - Byref types are not allowed in an open type declaration. Os tipos Byref não são permitidos em uma declaração de tipo aberto. @@ -502,11 +497,16 @@ 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. diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index 5a944c33961..5c35a4d3180 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -487,11 +487,6 @@ Атрибуты не могут быть применены к расширениям типа. - - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - - Byref types are not allowed in an open type declaration. Типы ByRef запрещены в объявлении открытого типа. @@ -502,11 +497,16 @@ 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#. diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index 5d78577f6d6..a5eab0e8d41 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -487,11 +487,6 @@ Öznitelikler tür uzantılarına uygulanamaz. - - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - - Byref types are not allowed in an open type declaration. Açık tür bildiriminde Byref türlerine izin verilmez. @@ -502,11 +497,16 @@ 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. diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index 1daac41fdc1..5aa158ea406 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -487,11 +487,6 @@ 属性不可应用于类型扩展。 - - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - - Byref types are not allowed in an open type declaration. 在开放类型声明中不允许使用 Byref 类型。 @@ -502,11 +497,16 @@ 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# 委托类型的方法的内联函数的参数。 diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index 303f47e5960..e8f1ffae44a 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -487,11 +487,6 @@ 屬性無法套用到類型延伸模組。 - - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - This expression uses the F#-defined implicit conversion '{0}' to convert type '{1}' to type '{2}'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn \"3389\". - - Byref types are not allowed in an open type declaration. 開放式類型宣告中不允許 Byref 類型。 @@ -502,11 +497,16 @@ 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# 委派類型之方法的內嵌函式參數。 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 index eed98877bd2..9208628103e 100644 --- a/tests/fsharp/core/auto-widen/preview/test.bsl +++ b/tests/fsharp/core/auto-widen/preview/test.bsl @@ -133,7 +133,7 @@ test.fsx(128,22,128,23): typecheck error FS3389: This expression uses a built-in 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 FS3391: This expression uses the F#-defined implicit conversion 'static member C.op_Implicit : x:int -> C' to convert type 'int' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3389". +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. @@ -145,11 +145,11 @@ test.fsx(145,18,145,19): typecheck error FS3390: This expression uses the implic 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 FS3390: This expression uses the implicit conversion 'Decimal.op_Implicit(value: int) : decimal' to convert type 'int' to type 'decimal'. +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 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(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. @@ -161,27 +161,27 @@ test.fsx(159,18,159,21): typecheck error FS3390: This expression uses the implic 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 FS3391: This expression uses the F#-defined implicit conversion 'static member C.op_Implicit : x:int -> C' to convert type 'int' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3389". +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 F#-defined 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 "3389". +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 F#-defined 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 "3389". +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 F#-defined 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 "3389". +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 F#-defined 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 "3389". +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 FS3390: This expression uses the implicit conversion 'Nullable.op_Implicit(value: int) : Nullable' to convert type 'int' to type 'Nullable'. +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 FS3390: This expression uses the implicit conversion 'Nullable.op_Implicit(value: int) : Nullable' to convert type 'int' to type 'Nullable'. +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. @@ -592,7 +592,7 @@ test.fsx(463,18,463,19): typecheck error FS0001: This expression was expected to but here has type 'int' -test.fsx(471,18,471,19): typecheck error FS3391: This expression uses the F#-defined implicit conversion 'static member C.op_Implicit : x:int -> C' to convert type 'int' to type 'C'. See https://aka.ms/fsharp-implicit-convs. This warning may be disabled using '#nowarn "3389". +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. @@ -602,25 +602,25 @@ test.fsx(482,18,482,21): typecheck error FS3387: This expression has type 'B' an 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 F#-defined 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 "3389". +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 F#-defined 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 "3389". +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 F#-defined 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 "3389". +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 F#-defined 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 "3389". +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 F#-defined 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 "3389". +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 F#-defined 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 "3389". +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 F#-defined 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 "3389". +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 F#-defined 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 "3389". +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' diff --git a/tests/fsharp/tests.fs b/tests/fsharp/tests.fs index d88a3a9577f..b0c86689720 100644 --- a/tests/fsharp/tests.fs +++ b/tests/fsharp/tests.fs @@ -86,6 +86,12 @@ module CoreTests = 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 From 17713a13c328c67e2c41b161baeb17c4ea966dc3 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 9 Aug 2021 20:37:02 +0100 Subject: [PATCH 39/42] Update FSharp.Test.Utilities.fsproj --- tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj b/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj index 07250b365ad..e1d3a54ed4f 100644 --- a/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj +++ b/tests/FSharp.Test.Utilities/FSharp.Test.Utilities.fsproj @@ -1,7 +1,7 @@  - net472;net5.0 + net472;net5.0 net5.0 win-x86;win-x64;linux-x64;osx-x64 $(AssetTargetFallback);portable-net45+win8+wp8+wpa81 From d2c3a335d17940a49a12f2ea6b9f8a9cf61c0245 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Mon, 9 Aug 2021 20:37:45 +0100 Subject: [PATCH 40/42] Update FSharp.Compiler.Service.Tests.fsproj --- .../FSharp.Compiler.Service.Tests.fsproj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 1f6241fa5d8..3b89936fed6 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj @@ -2,7 +2,8 @@ Exe - net472;net5.0 + net472;net5.0 + net5.0 $(NoWarn);44;75; true false @@ -81,4 +82,4 @@ - \ No newline at end of file + From c29bf2b9b58155aaa1c9c45008c2979c8f2a8658 Mon Sep 17 00:00:00 2001 From: KevinRansom Date: Mon, 9 Aug 2021 14:36:53 -0700 Subject: [PATCH 41/42] Fix merge issue --- .../FSharp.Compiler.Service.Tests.fsproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 3b89936fed6..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 @@ -80,6 +80,7 @@ + From 0147f34ef83518d72d596ea8c00823a12d80b9d6 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 10 Aug 2021 20:02:00 +0100 Subject: [PATCH 42/42] Update CheckExpressions.fs --- src/fsharp/CheckExpressions.fs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 5bfa9149d8e..ffc9fc6f40c 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -5834,7 +5834,11 @@ and TcExprUndelayed cenv (overallTy: 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, (SynExpr.Const (SynConst.Int32 1, m)), m, DebugPointForTarget.No)) + 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