Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP, FS-1043] Extension members visible to trait constraints #3582

Closed
wants to merge 37 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
7822a13
First attempt
Aug 17, 2017
f977d3f
add testfile
TobyShaw Aug 18, 2017
898d97b
First draft, messy solution
Sep 14, 2017
888f1cf
Merge branch 'extensionconstraints' of https://github.com/TobyShaw/vi…
Sep 14, 2017
1b41d93
merge with master
dsyme Sep 25, 2017
9efe7ef
merge with master
dsyme Sep 25, 2017
7121bc3
work towards freshening things correctly
Sep 25, 2017
bdfa7b3
fix build
Sep 25, 2017
1fa2326
prototype for extension solutions to trait constraints
Sep 25, 2017
baf3f15
Merge branch 'master' of http://github.com/Microsoft/visualfsharp int…
dsyme Sep 27, 2017
db3f298
resolve
dsyme Sep 27, 2017
b8c95f4
resolve and merge
dsyme Sep 27, 2017
f75a2ab
resolve and merge
dsyme Sep 27, 2017
072cbbb
minor cleanup
dsyme Sep 27, 2017
2e78b58
merge
Sep 27, 2017
9bdfb21
it works
Sep 27, 2017
96502ea
minor cleanup
dsyme Sep 27, 2017
f287f20
various fixes
Sep 29, 2017
100ff18
Merge branch 'master' of http://github.com/Microsoft/visualfsharp int…
Oct 2, 2017
91d1a35
support extenstion properties on generic types
Oct 2, 2017
7513645
range of fixes to freshening and trait printing
Oct 2, 2017
010bf0f
fix build
Oct 2, 2017
d0bc0b3
Merge branch 'master' of http://github.com/Microsoft/visualfsharp int…
Oct 2, 2017
36d26e7
reduce diff
Oct 2, 2017
434b095
merge with master
Oct 2, 2017
000e34d
Merge branch 'master' into extensionconstraints
dsyme Oct 3, 2017
8b601f2
Fix Oddities in statically resolved method constraints and method ove…
Nov 17, 2017
77447d6
no return type needed before proceeding to overload resolution
dsyme Nov 18, 2017
c67437d
fix tests
dsyme Nov 18, 2017
827f38a
Merge branch 'master' of http://github.com/Microsoft/visualfsharp int…
Dec 1, 2017
dbe243c
Merge branch 'fix-3814' of https://github.com/dsyme/visualfsharp into…
Dec 1, 2017
ec80c48
integrate master
Dec 1, 2017
4e7183e
minimize diff and integrate fix
Dec 1, 2017
4ca7ea8
minimize diff
Dec 1, 2017
fa31367
minimize diff
Dec 1, 2017
281e1f0
minimize diff
Dec 1, 2017
58787bd
minimize diff
Dec 1, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/fsharp/AccessibilityLogic.fs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ type AccessorDomain =
/// An AccessorDomain which returns all items
| AccessibleFromSomewhere

interface TraitAccessorDomain

// Hashing and comparison is used for the memoization tables keyed by an accessor domain.
// It is dependent on a TcGlobals because of the TyconRef in the data structure
static member CustomGetHashCode(ad:AccessorDomain) =
Expand All @@ -48,6 +50,7 @@ type AccessorDomain =
| AccessibleFromEverywhere -> 2
| AccessibleFromSomeFSharpCode -> 3
| AccessibleFromSomewhere -> 4

static member CustomEquals(g:TcGlobals, ad1:AccessorDomain, ad2:AccessorDomain) =
match ad1, ad2 with
| AccessibleFrom(cs1,tc1), AccessibleFrom(cs2,tc2) -> (cs1 = cs2) && (match tc1,tc2 with None,None -> true | Some tc1, Some tc2 -> tyconRefEq g tc1 tc2 | _ -> false)
Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/CheckFormatStrings.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ open Microsoft.FSharp.Compiler.ConstraintSolver
type FormatItem = Simple of TType | FuncAndVal

let copyAndFixupFormatTypar m tp =
let _,_,tinst = FreshenAndFixupTypars m TyparRigidity.Flexible [] [] [tp]
let _,_,tinst = FreshenAndFixupTypars None m TyparRigidity.Flexible [] [] [tp]
List.head tinst

let lowestDefaultPriority = 0 (* See comment on TyparConstraint.DefaultsTo *)
Expand Down
3 changes: 1 addition & 2 deletions src/fsharp/CompileOptions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1269,7 +1269,6 @@ let ApplyAllOptimizations (tcConfig:TcConfig, tcGlobals, tcVal, outfile, importM
let optSettings = tcConfig.optSettings
let optSettings = { optSettings with abstractBigTargets = tcConfig.doTLR }
let optSettings = { optSettings with reportingPhase = true }

let results,(optEnvFirstLoop,_,_,_) =
((optEnv0,optEnv0,optEnv0,SignatureHidingInfo.Empty),implFiles) ||> List.mapFold (fun (optEnvFirstLoop,optEnvExtraLoop,optEnvFinalSimplify,hidden) implFile ->

Expand Down Expand Up @@ -1356,7 +1355,7 @@ let GenerateIlxCode (ilxBackend, isInteractiveItExpr, isInteractiveOnMono, tcCon
isInteractiveItExpr = isInteractiveItExpr
alwaysCallVirt = tcConfig.alwaysCallVirt }

ilxGenerator.GenerateCode (ilxGenOpts, optimizedImpls, topAttrs.assemblyAttrs,topAttrs.netModuleAttrs)
ilxGenerator.GenerateCode (ilxGenOpts, optimizedImpls, topAttrs.assemblyAttrs, topAttrs.netModuleAttrs)

//----------------------------------------------------------------------------
// Assembly ref normalization: make sure all assemblies are referred to
Expand Down
585 changes: 354 additions & 231 deletions src/fsharp/ConstraintSolver.fs

Large diffs are not rendered by default.

93 changes: 61 additions & 32 deletions src/fsharp/ConstraintSolver.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ open Microsoft.FSharp.Compiler.AbstractIL
open Microsoft.FSharp.Compiler.AbstractIL.Internal
open Microsoft.FSharp.Compiler.AbstractIL.Internal.Library
open Microsoft.FSharp.Compiler
open Microsoft.FSharp.Compiler.NameResolution
open Microsoft.FSharp.Compiler.AccessibilityLogic
open Microsoft.FSharp.Compiler.Ast
open Microsoft.FSharp.Compiler.ErrorLogger
Expand Down Expand Up @@ -37,45 +38,67 @@ val NewErrorMeasure : unit -> Measure
/// Create a list of inference type variables, one for each element in the input list
val NewInferenceTypes : 'a list -> TType list

/// Freshen a trait for use at a particular location
type TraitFreshener = (TraitConstraintInfo -> TraitPossibleExtensionMemberSolutions * TraitAccessorDomain)

/// Given a set of formal type parameters and their constraints, make new inference type variables for
/// each and ensure that the constraints on the new type variables are adjusted to refer to these.
val FreshenAndFixupTypars : range -> TyparRigidity -> Typars -> TType list -> Typars -> Typars * TyparInst * TType list
val FreshenAndFixupTypars : TraitFreshener option -> range -> TyparRigidity -> Typars -> TType list -> Typars -> Typars * TyparInst * TType list

/// Make new type inference variables for the use of a generic construct at a particular location
val FreshenTypeInst : TraitFreshener option -> range -> Typars -> Typars * TyparInst * TType list

val FreshenTypeInst : range -> Typars -> Typars * TyparInst * TType list
/// Make new type inference variables for the use of a generic construct at a particular location
val FreshenTypars : TraitFreshener option -> range -> Typars -> TType list

val FreshenTypars : range -> Typars -> TType list
/// Make new type inference variables for the use of a method at a particular location
val FreshenMethInfo : TraitFreshener option -> range -> MethInfo -> TType list

val FreshenMethInfo : range -> MethInfo -> TType list
/// Get the trait freshener for a particular location
val GetTraitFreshner : AccessorDomain -> NameResolutionEnv -> TraitFreshener

[<RequireQualifiedAccess>]
/// Information about the context of a type equation.
/// Information about the context of a type equation, for better error reporting
type ContextInfo =
/// No context was given.
| NoContext
/// The type equation comes from an IF expression.
| IfExpression of range
/// The type equation comes from an omitted else branch.
| OmittedElseBranch of range
/// The type equation comes from a type check of the result of an else branch.
| ElseBranchResult of range
/// The type equation comes from the verification of record fields.
| RecordFields
/// The type equation comes from the verification of a tuple in record fields.
| TupleInRecordFields
/// The type equation comes from a list or array constructor
| CollectionElement of bool * range
/// The type equation comes from a return in a computation expression.
| ReturnInComputationExpression
/// The type equation comes from a yield in a computation expression.
| YieldInComputationExpression
/// The type equation comes from a runtime type test.
| RuntimeTypeTest of bool
/// The type equation comes from an downcast where a upcast could be used.
| DowncastUsedInsteadOfUpcast of bool
/// The type equation comes from a return type of a pattern match clause (not the first clause).
| FollowingPatternMatchClause of range
/// The type equation comes from a pattern match guard.
| PatternMatchGuard of range

/// No context was given.
| NoContext

/// The type equation comes from an IF expression.
| IfExpression of range

/// The type equation comes from an omitted else branch.
| OmittedElseBranch of range

/// The type equation comes from a type check of the result of an else branch.
| ElseBranchResult of range

/// The type equation comes from the verification of record fields.
| RecordFields

/// The type equation comes from the verification of a tuple in record fields.
| TupleInRecordFields

/// The type equation comes from a list or array constructor
| CollectionElement of bool * range

/// The type equation comes from a return in a computation expression.
| ReturnInComputationExpression

/// The type equation comes from a yield in a computation expression.
| YieldInComputationExpression

/// The type equation comes from a runtime type test.
| RuntimeTypeTest of bool

/// The type equation comes from an downcast where a upcast could be used.
| DowncastUsedInsteadOfUpcast of bool

/// The type equation comes from a return type of a pattern match clause (not the first clause).
| FollowingPatternMatchClause of range

/// The type equation comes from a pattern match guard.
| PatternMatchGuard of range


exception ConstraintSolverTupleDiffLengths of DisplayEnv * TType list * TType list * range * range
Expand Down Expand Up @@ -117,7 +140,10 @@ type OptionalTrace =
val SimplifyMeasuresInTypeScheme : TcGlobals -> bool -> Typars -> TType -> TyparConstraint list -> Typars
val SolveTyparEqualsTyp : ConstraintSolverEnv -> int -> range -> OptionalTrace -> TType -> TType -> OperationResult<unit>
val SolveTypEqualsTypKeepAbbrevs : ConstraintSolverEnv -> int -> range -> OptionalTrace -> TType -> TType -> OperationResult<unit>

/// Canonicalize constraints prior to generalization
val CanonicalizeRelevantMemberConstraints : ConstraintSolverEnv -> int -> OptionalTrace -> Typars -> OperationResult<unit>

val ResolveOverloading : ConstraintSolverEnv -> OptionalTrace -> string -> ndeep: int -> TraitConstraintInfo option -> int * int -> AccessorDomain -> CalledMeth<Expr> list -> bool -> TType option -> CalledMeth<Expr> option * OperationResult<unit>
val UnifyUniqueOverloading : ConstraintSolverEnv -> int * int -> string -> AccessorDomain -> CalledMeth<SynExpr> list -> TType -> OperationResult<bool>
val EliminateConstraintsForGeneralizedTypars : ConstraintSolverEnv -> OptionalTrace -> Typars -> unit
Expand All @@ -142,8 +168,11 @@ val AddCxTypeIsUnmanaged : DisplayEnv -> ConstraintSolverSt
val AddCxTypeIsEnum : DisplayEnv -> ConstraintSolverState -> range -> OptionalTrace -> TType -> TType -> unit
val AddCxTypeIsDelegate : DisplayEnv -> ConstraintSolverState -> range -> OptionalTrace -> TType -> TType -> TType -> unit

val CodegenWitnessThatTypSupportsTraitConstraint : TcValF -> TcGlobals -> ImportMap -> range -> TraitConstraintInfo -> Expr list -> OperationResult<Expr option>
val CodegenWitnessThatTypSupportsTraitConstraint : TcValF -> TcGlobals -> ImportMap -> range -> traitInfo: TraitConstraintInfo -> argExprs: Expr list -> OperationResult<Expr option>

val ChooseTyparSolutionAndSolve : ConstraintSolverState -> DisplayEnv -> Typar -> unit

/// Get the type variables that may help provide solutions to a statically resolved member trait constraint
val GetSupportOfMemberConstraint : ConstraintSolverEnv -> TraitConstraintInfo -> Typar list

val IsApplicableMethApprox : TcGlobals -> ImportMap -> range -> MethInfo -> TType -> bool
2 changes: 1 addition & 1 deletion src/fsharp/FSComp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1071,7 +1071,7 @@ lexIndentOffForML,"Consider using a file with extension '.ml' or '.mli' instead"
1212,tcOptionalArgsMustComeAfterNonOptionalArgs,"Optional arguments must come at the end of the argument list, after any non-optional arguments"
1213,tcConditionalAttributeUsage,"Attribute 'System.Diagnostics.ConditionalAttribute' is only valid on methods or attribute classes"
#1214,monoRegistryBugWorkaround,"Could not determine highest installed .NET framework version from Registry keys, using version 2.0"
1215,tcMemberOperatorDefinitionInExtrinsic,"Extension members cannot provide operator overloads. Consider defining the operator as part of the type definition instead."
#1215,tcMemberOperatorDefinitionInExtrinsic,"Extension members cannot provide operator overloads. Consider defining the operator as part of the type definition instead."
1216,ilwriteMDBFileNameCannotBeChangedWarning,"The name of the MDB file must be <assembly-file-name>.mdb. The --pdb option will be ignored."
1217,ilwriteMDBMemberMissing,"MDB generation failed. Could not find compatible member %s"
1218,ilwriteErrorCreatingMdb,"Cannot generate MDB debug information. Failed to load the 'MonoSymbolWriter' type from the 'Mono.CompilerServices.SymbolWriter.dll' assembly."
Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/FindUnsolved.fs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ and accOp cenv env (op,tyargs,args,_m) =
accTypeInst cenv env enclTypeArgs
accTypeInst cenv env methTypeArgs
accTypeInst cenv env tys
| TOp.TraitCall(TTrait(tys,_nm,_,argtys,rty,_sln)) ->
| TOp.TraitCall(TTrait(tys, _nm, _, argtys, rty, _sln, _extSlns, _ad)) ->
argtys |> accTypeInst cenv env
rty |> Option.iter (accTy cenv env)
tys |> List.iter (accTy cenv env)
Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/IlxGen.fs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ type cenv =
amap: ImportMap
intraAssemblyInfo : IlxGenIntraAssemblyInfo
/// Cache methods with SecurityAttribute applied to them, to prevent unnecessary calls to ExistsInEntireHierarchyOfType
casApplied : Dictionary<Stamp,bool>
casApplied : Dictionary<Stamp,bool>
/// Used to apply forced inlining optimizations to witnesses generated late during codegen
mutable optimizeDuringCodeGen : (Expr -> Expr) }

Expand Down
4 changes: 2 additions & 2 deletions src/fsharp/InfoReader.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ open Microsoft.FSharp.Compiler.AbstractIL.IL
open Microsoft.FSharp.Compiler.AbstractIL.Internal
open Microsoft.FSharp.Compiler.AbstractIL.Internal.Library

open Microsoft.FSharp.Compiler
open Microsoft.FSharp.Compiler
open Microsoft.FSharp.Compiler.AccessibilityLogic
open Microsoft.FSharp.Compiler.Ast
open Microsoft.FSharp.Compiler.AttributeChecking
Expand All @@ -20,7 +20,7 @@ open Microsoft.FSharp.Compiler.Tastops
open Microsoft.FSharp.Compiler.TcGlobals

/// Use the given function to select some of the member values from the members of an F# type
let private SelectImmediateMemberVals g optFilter f (tcref:TyconRef) =
let SelectImmediateMemberVals g optFilter f (tcref:TyconRef) =
let chooser (vref:ValRef) =
match vref.MemberInfo with
// The 'when' condition is a workaround for the fact that values providing
Expand Down
22 changes: 15 additions & 7 deletions src/fsharp/MethodCalls.fs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,9 @@ type CalledMeth<'T>
member x.TotalNumUnnamedCallerArgs = x.ArgSets |> List.sumBy (fun x -> x.NumUnnamedCallerArgs)
member x.TotalNumAssignedNamedArgs = x.ArgSets |> List.sumBy (fun x -> x.NumAssignedNamedArgs)

override x.ToString() = "call to " + minfo.ToString()


let NamesOfCalledArgs (calledArgs: CalledArg list) =
calledArgs |> List.choose (fun x -> x.NameOpt)

Expand Down Expand Up @@ -630,13 +633,13 @@ let BuildFSharpMethodApp g m (vref: ValRef) vexp vexprty (args: Exprs) =
retTy

/// Build a call to an F# method.
let BuildFSharpMethodCall g m (typ,vref:ValRef) valUseFlags minst args =
let vexp = Expr.Val (vref,valUseFlags,m)
let BuildFSharpMethodCall g m (vref:ValRef) valUseFlags declaringTypeInst minst args =
let vexp = Expr.Val (vref, valUseFlags, m)
let vexpty = vref.Type
let tpsorig,tau = vref.TypeScheme
let vtinst = argsOfAppTy g typ @ minst
if tpsorig.Length <> vtinst.Length then error(InternalError("BuildFSharpMethodCall: unexpected List.length mismatch",m))
let expr = mkTyAppExpr m (vexp,vexpty) vtinst
let vtinst = declaringTypeInst @ minst
if tpsorig.Length <> vtinst.Length then error(InternalError("BuildFSharpMethodCall: unexpected typar length mismatch",m))
let expr = mkTyAppExpr m (vexp, vexpty) vtinst
let exprty = instType (mkTyparInst tpsorig vtinst) tau
BuildFSharpMethodApp g m vref expr exprty args

Expand All @@ -645,15 +648,20 @@ let BuildFSharpMethodCall g m (typ,vref:ValRef) valUseFlags minst args =
/// calls to the type-directed solutions to member constraints.
let MakeMethInfoCall amap m minfo minst args =
let valUseFlags = NormalValUse // correct unless if we allow wild trait constraints like "T has a ctor and can be used as a parent class"

match minfo with

| ILMeth(g,ilminfo,_) ->
let direct = not minfo.IsVirtual
let isProp = false // not necessarily correct, but this is only used post-creflect where this flag is irrelevant
BuildILMethInfoCall g amap m isProp ilminfo valUseFlags minst direct args |> fst
| FSMeth(g,typ,vref,_) ->
BuildFSharpMethodCall g m (typ,vref) valUseFlags minst args |> fst

| FSMeth(g, _, vref, _) ->
BuildFSharpMethodCall g m vref valUseFlags minfo.DeclaringTypeInst minst args |> fst

| DefaultStructCtor(_,typ) ->
mkDefault (m,typ)

#if !NO_EXTENSIONTYPING
| ProvidedMeth(amap,mi,_,m) ->
let isProp = false // not necessarily correct, but this is only used post-creflect where this flag is irrelevant
Expand Down
Loading