@@ -959,49 +959,64 @@ let internal WithImplicitHome (tcConfigB, dir) f =
959959 try f()
960960 finally tcConfigB.implicitIncludeDir <- old
961961
962- let internal importReflectionType amap ( reflectionTy : Type ) =
963- let reflectionTyToILTypeRef ( reflectionTy : Type ) =
964- let aref = ILAssemblyRef.FromAssemblyName( reflectionTy.Assembly.GetName())
965- let scoref = ILScopeRef.Assembly aref
966-
967- let fullName = reflectionTy.FullName
968- let index = fullName.IndexOf( " [" )
969- let fullName =
970- if index = - 1 then
971- fullName
972- else
973- fullName.Substring( 0 , index - 1 )
962+ let internal convertReflectionTypeToILTypeRef ( reflectionTy : Type ) =
963+ if reflectionTy.Assembly.IsDynamic then
964+ raise ( NotSupportedException( sprintf " Unable to import type, %A , from a dynamic assembly." reflectionTy))
965+
966+ if not reflectionTy.IsPublic && not reflectionTy.IsNestedPublic then
967+ invalidOp ( sprintf " Cannot import the non-public type, %A ." reflectionTy)
974968
975- let isTop = reflectionTy.DeclaringType = null
976- if isTop then
977- ILTypeRef.Create( scoref, [], fullName)
969+ let aref = ILAssemblyRef.FromAssemblyName( reflectionTy.Assembly.GetName())
970+ let scoref = ILScopeRef.Assembly aref
971+
972+ let fullName = reflectionTy.FullName
973+ let index = fullName.IndexOf( " [" )
974+ let fullName =
975+ if index = - 1 then
976+ fullName
978977 else
979- let names = String.split StringSplitOptions.None [| " +" ; " ." |] fullName
980- let enc = names.[.. names.Length - 2 ]
981- let nm = names.[ names.Length - 1 ]
982- ILTypeRef.Create( scoref, List.ofArray enc, nm)
983-
984- let rec reflectionTyToILType ( reflectionTy : Type ) =
985- let tref = reflectionTyToILTypeRef reflectionTy
986- let genericArgs =
987- reflectionTy.GenericTypeArguments
988- |> Seq.map reflectionTyToILType
989- |> List.ofSeq
990-
991- let boxity =
992- if reflectionTy.IsValueType then
993- ILBoxity.AsValue
978+ fullName.Substring( 0 , index)
979+
980+ let isTop = reflectionTy.DeclaringType = null
981+ if isTop then
982+ ILTypeRef.Create( scoref, [], fullName)
983+ else
984+ let names = String.split StringSplitOptions.None [| " +" ; " ." |] fullName
985+ let enc = names.[.. names.Length - 2 ]
986+ let nm = names.[ names.Length - 1 ]
987+ ILTypeRef.Create( scoref, List.ofArray enc, nm)
988+
989+ let rec internal convertReflectionTypeToILType ( reflectionTy : Type ) =
990+ let reflectionTy =
991+ // Special case functions.
992+ if FSharp.Reflection.FSharpType.IsFunction reflectionTy then
993+ let ctors = reflectionTy.GetConstructors( BindingFlags.Public ||| BindingFlags.NonPublic ||| BindingFlags.Instance)
994+ if ctors.Length = 1 &&
995+ ctors.[ 0 ]. GetCustomAttribute< CompilerGeneratedAttribute>() <> null &&
996+ not ctors.[ 0 ]. IsPublic &&
997+ PrettyNaming.IsCompilerGeneratedName reflectionTy.Name then
998+ let rec get ( typ : Type ) = if FSharp.Reflection.FSharpType.IsFunction typ.BaseType then get typ.BaseType else typ
999+ get reflectionTy
9941000 else
995- ILBoxity.AsObject
1001+ reflectionTy
1002+ else
1003+ reflectionTy
9961004
997- let tspec = ILTypeSpec.Create( tref, genericArgs)
1005+ let tref = convertReflectionTypeToILTypeRef reflectionTy
1006+ let genericArgs =
1007+ reflectionTy.GenericTypeArguments
1008+ |> Seq.map convertReflectionTypeToILType
1009+ |> List.ofSeq
9981010
999- mkILTy boxity tspec
1011+ let boxity =
1012+ if reflectionTy.IsValueType then
1013+ ILBoxity.AsValue
1014+ else
1015+ ILBoxity.AsObject
10001016
1001- let rec import ( ilTy : ILType ) =
1002- Import.ImportILType amap range0 ( ilTy.GenericArgs |> List.map import) ilTy
1017+ let tspec = ILTypeSpec.Create( tref, genericArgs)
10031018
1004- import ( reflectionTyToILType reflectionTy )
1019+ mkILTy boxity tspec
10051020
10061021let internal mkBoundValueTypedImpl tcGlobals m moduleName name ty =
10071022 let vis = Accessibility.TAccess([])
@@ -1507,51 +1522,90 @@ type internal FsiDynamicCompiler
15071522 | _ ->
15081523 None
15091524
1510- member __.AddBoundValue ( ctok , errorLogger : ErrorLogger , istate , name : string , value : obj ) =
1511- if String.IsNullOrWhiteSpace name then
1512- errorLogger.Error( Error( FSComp.SR.parsIdentifierExpected(), range0))
1525+ member private this.ImportReflectionType ( ctok , istate , reflectionTy ) =
1526+ let amap = istate.tcImports.GetImportMap()
1527+
1528+ let resolveAssemblyRefOfILType istate ( ilTy : ILType ) =
1529+ let tcImports = istate.tcImports
1530+
1531+ if ilTy.IsNominal then
1532+ match ilTy.TypeRef.Scope with
1533+ | ILScopeRef.Assembly aref ->
1534+ // Simple name unification. If it fails, then try to resolve the assembly.
1535+ if tcImports.TryFindDllInfo( ctok, range0, aref.Name, lookupOnly = true ) .IsNone then
1536+ this.EvalRequireReference( ctok, istate, range0, aref.Name)
1537+ |> snd
1538+ else
1539+ istate
1540+ | _ ->
1541+ istate
1542+ else
1543+ istate
1544+
1545+ let rec import istate ( ilTy : ILType ) =
1546+ let istate = resolveAssemblyRefOfILType istate ilTy
1547+ let istate , tinst =
1548+ ( ilTy.GenericArgs, ( istate, []))
1549+ ||> List.foldBack ( fun ilGenericArgTy ( istate , tinst ) ->
1550+ let istate , ty = import istate ilGenericArgTy
1551+ ( istate, ty :: tinst))
1552+ istate, Import.ImportILType amap range0 tinst ilTy
1553+
1554+ import istate ( convertReflectionTypeToILType reflectionTy)
15131555
1514- // Verify that the name is a valid identifier for a value.
1515- SourceCodeServices.Lexer.FSharpLexer.Lex( SourceText.ofString name,
1516- let mutable foundOne = false
1517- fun t ->
1518- if not t.IsIdentifier || foundOne then
1519- errorLogger.Error( Error( FSComp.SR.parsIdentifierExpected(), range0))
1520- foundOne <- true )
1556+ member this.AddBoundValue ( ctok , errorLogger : ErrorLogger , istate , name : string , value : obj ) =
1557+ try
1558+ match value with
1559+ | null -> nullArg " value"
1560+ | _ -> ()
15211561
1522- if PrettyNaming.IsCompilerGeneratedName name then
1523- errorLogger.Warning ( Error ( FSComp.SR.lexhlpIdentifiersContainingAtSymbolReserved (), range0 ))
1562+ if String.IsNullOrWhiteSpace name then
1563+ invalidArg " name " " Name cannot be null or white-space. "
15241564
1525- let amap = istate.tcImports.GetImportMap()
1526- let ty = importReflectionType amap ( value.GetType())
1565+ // Verify that the name is a valid identifier for a value.
1566+ SourceCodeServices.Lexer.FSharpLexer.Lex( SourceText.ofString name,
1567+ let mutable foundOne = false
1568+ fun t ->
1569+ if not t.IsIdentifier || foundOne then
1570+ invalidArg " name" " Name is not a valid identifier."
1571+ foundOne <- true )
15271572
1528- let i = nextFragmentId()
1529- let prefix = mkFragmentPath i
1530- let prefixPath = pathOfLid prefix
1531- let qualifiedName = ComputeQualifiedNameOfFileFromUniquePath ( rangeStdin, prefixPath)
1573+ if PrettyNaming.IsCompilerGeneratedName name then
1574+ invalidArg " name" ( FSComp.SR.lexhlpIdentifiersContainingAtSymbolReserved() |> snd)
15321575
1533- let tcConfig = TcConfig.Create( tcConfigB, validate= false )
1576+ let istate , ty = this.ImportReflectionType( ctok, istate, value.GetType())
1577+ let amap = istate.tcImports.GetImportMap()
15341578
1535- // Build a simple module with a single 'let' decl with a default value.
1536- let moduleOrNamespace , v , impl = mkBoundValueTypedImpl istate.tcGlobals range0 qualifiedName.Text name ty
1537- let tcEnvAtEndOfLastInput =
1538- TypeChecker.AddLocalSubModule tcGlobals amap range0 istate.tcState.TcEnvFromImpls moduleOrNamespace
1539- |> TypeChecker.AddLocalVal TcResultsSink.NoSink range0 v
1579+ let i = nextFragmentId()
1580+ let prefix = mkFragmentPath i
1581+ let prefixPath = pathOfLid prefix
1582+ let qualifiedName = ComputeQualifiedNameOfFileFromUniquePath ( rangeStdin, prefixPath)
15401583
1541- // Generate IL for the given typled impl and create new interactive state.
1542- let ilxGenerator = istate.ilxGenerator
1543- let isIncrementalFragment = true
1544- let showTypes = false
1545- let declaredImpls = [ impl]
1546- let codegenResults , optEnv , fragName = ProcessTypedImpl( errorLogger, istate.optEnv, istate.tcState, tcConfig, false , EmptyTopAttrs, prefix, isIncrementalFragment, declaredImpls, ilxGenerator)
1547- let istate , declaredImpls = ProcessCodegenResults( ctok, errorLogger, istate, optEnv, istate.tcState, tcConfig, prefix, showTypes, isIncrementalFragment, fragName, declaredImpls, ilxGenerator, codegenResults)
1548- let newState = { istate with tcState = istate.tcState.NextStateAfterIncrementalFragment tcEnvAtEndOfLastInput }
1549-
1550- // Force set the val with the given value obj.
1551- let ctxt = valuePrinter.GetEvaluationContext( newState.emEnv)
1552- ilxGenerator.ForceSetGeneratedValue( ctxt, v, value)
1553-
1554- fst ( processContents newState declaredImpls)
1584+ let tcConfig = TcConfig.Create( tcConfigB, validate= false )
1585+
1586+ // Build a simple module with a single 'let' decl with a default value.
1587+ let moduleOrNamespace , v , impl = mkBoundValueTypedImpl istate.tcGlobals range0 qualifiedName.Text name ty
1588+ let tcEnvAtEndOfLastInput =
1589+ TypeChecker.AddLocalSubModule tcGlobals amap range0 istate.tcState.TcEnvFromImpls moduleOrNamespace
1590+ |> TypeChecker.AddLocalVal TcResultsSink.NoSink range0 v
1591+
1592+ // Generate IL for the given typled impl and create new interactive state.
1593+ let ilxGenerator = istate.ilxGenerator
1594+ let isIncrementalFragment = true
1595+ let showTypes = false
1596+ let declaredImpls = [ impl]
1597+ let codegenResults , optEnv , fragName = ProcessTypedImpl( errorLogger, istate.optEnv, istate.tcState, tcConfig, false , EmptyTopAttrs, prefix, isIncrementalFragment, declaredImpls, ilxGenerator)
1598+ let istate , declaredImpls = ProcessCodegenResults( ctok, errorLogger, istate, optEnv, istate.tcState, tcConfig, prefix, showTypes, isIncrementalFragment, fragName, declaredImpls, ilxGenerator, codegenResults)
1599+ let newState = { istate with tcState = istate.tcState.NextStateAfterIncrementalFragment tcEnvAtEndOfLastInput }
1600+
1601+ // Force set the val with the given value obj.
1602+ let ctxt = valuePrinter.GetEvaluationContext( newState.emEnv)
1603+ ilxGenerator.ForceSetGeneratedValue( ctxt, v, value)
1604+
1605+ processContents newState declaredImpls
1606+ with
1607+ | ex ->
1608+ istate, CompletedWithReportedError( StopProcessingExn( Some ex))
15551609
15561610 member __.GetInitialInteractiveState () =
15571611 let tcConfig = TcConfig.Create( tcConfigB, validate= false )
@@ -2412,8 +2466,8 @@ type internal FsiInteractionProcessor
24122466 member __.AddBoundValue ( ctok , errorLogger , name , value : obj ) =
24132467 currState
24142468 |> InteractiveCatch errorLogger ( fun istate ->
2415- fsiDynamicCompiler.AddBoundValue( ctok, errorLogger, istate, name, value), Completed None ) |> fst
2416- |> setCurrState
2469+ fsiDynamicCompiler.AddBoundValue( ctok, errorLogger, istate, name, value))
2470+ |> commitResult
24172471
24182472 member __.PartialAssemblySignatureUpdated = event.Publish
24192473
@@ -2937,20 +2991,14 @@ type FsiEvaluationSession (fsi: FsiEvaluationSessionHostConfig, argv:string[], i
29372991 fsiDynamicCompiler.TryFindBoundValue( fsiInteractionProcessor.CurrentState, name)
29382992
29392993 member __.AddBoundValue ( name : string , value : obj ) =
2940- match value with
2941- | null -> nullArg " value"
2942- | _ -> ()
2943-
29442994 // Explanation: When the user of the FsiInteractiveSession object calls this method, the
29452995 // code is parsed, checked and evaluated on the calling thread. This means EvalExpression
29462996 // is not safe to call concurrently.
29472997 let ctok = AssumeCompilationThreadWithoutEvidence()
29482998
2949- let errorOptions = TcConfig.Create( tcConfigB, validate = false ) .errorSeverityOptions
2950- let errorLogger = CompilationErrorLogger( " AddBoundValue" , errorOptions)
29512999 fsiInteractionProcessor.AddBoundValue( ctok, errorLogger, name, value)
2952- let errs = errorLogger.GetErrors ()
2953- ErrorHelpers.CreateErrorInfos ( errorOptions , true , " input.fsx " , errs , true )
3000+ |> commitResult
3001+ |> ignore
29543002
29553003 /// Performs these steps:
29563004 /// - Load the dummy interaction, if any
0 commit comments