Skip to content

Commit

Permalink
Nullness interop - import of C#-emitted metadata (#16423)
Browse files Browse the repository at this point in the history
  • Loading branch information
T-Gro authored Jan 17, 2024
1 parent ed7854b commit d697c63
Show file tree
Hide file tree
Showing 38 changed files with 2,130 additions and 975 deletions.
20 changes: 19 additions & 1 deletion src/Compiler/AbstractIL/il.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -868,7 +868,13 @@ type ILAttributes =

/// Represents the efficiency-oriented storage of ILAttributes in another item.
[<NoEquality; NoComparison>]
type ILAttributesStored
type ILAttributesStored =
/// Computed by ilread.fs based on metadata index
| Reader of (int32 -> ILAttribute[])
/// Already computed
| Given of ILAttributes

member GetCustomAttrs: int32 -> ILAttributes

/// Method parameters and return values.
[<RequireQualifiedAccess; NoEquality; NoComparison>]
Expand Down Expand Up @@ -1069,6 +1075,8 @@ type ILMethodDef =
member IsEntryPoint: bool
member GenericParams: ILGenericParameterDefs
member CustomAttrs: ILAttributes
member MetadataIndex: int32
member CustomAttrsStored: ILAttributesStored
member ParameterTypes: ILTypes
member IsIL: bool
member Code: ILCode option
Expand Down Expand Up @@ -1242,6 +1250,10 @@ type ILFieldDef =

member CustomAttrs: ILAttributes

member MetadataIndex: int32

member CustomAttrsStored: ILAttributesStored

member IsStatic: bool

member IsSpecialName: bool
Expand Down Expand Up @@ -1325,6 +1337,8 @@ type ILEventDef =
member FireMethod: ILMethodRef option
member OtherMethods: ILMethodRef list
member CustomAttrs: ILAttributes
member MetadataIndex: int32
member CustomAttrsStored: ILAttributesStored
member IsSpecialName: bool
member IsRTSpecialName: bool

Expand Down Expand Up @@ -1387,6 +1401,8 @@ type ILPropertyDef =
member Init: ILFieldInit option
member Args: ILTypes
member CustomAttrs: ILAttributes
member MetadataIndex: int32
member CustomAttrsStored: ILAttributesStored
member IsSpecialName: bool
member IsRTSpecialName: bool

Expand Down Expand Up @@ -1538,6 +1554,8 @@ type ILTypeDef =
member Events: ILEventDefs
member Properties: ILPropertyDefs
member CustomAttrs: ILAttributes
member MetadataIndex: int32
member CustomAttrsStored: ILAttributesStored
member IsClass: bool
member IsStruct: bool
member IsInterface: bool
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/Checking/AccessibilityLogic.fs
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,8 @@ let IsILEventInfoAccessible g amap m ad einfo =

let private IsILMethInfoAccessible g amap m adType ad ilminfo =
match ilminfo with
| ILMethInfo (_, ty, None, mdef, _) -> IsILTypeAndMemberAccessible g amap m adType ad (ILTypeInfo.FromType g ty) mdef.Access
| ILMethInfo (_, _, Some declaringTyconRef, mdef, _) -> IsILMemberAccessible g amap m declaringTyconRef ad mdef.Access
| ILMethInfo (_, IlType ty, mdef, _) -> IsILTypeAndMemberAccessible g amap m adType ad ty mdef.Access
| ILMethInfo (_, CSharpStyleExtension(declaring=declaringTyconRef), mdef, _) -> IsILMemberAccessible g amap m declaringTyconRef ad mdef.Access

let GetILAccessOfILPropInfo (ILPropInfo(tinfo, pdef)) =
let tdef = tinfo.RawMetadata
Expand Down
9 changes: 6 additions & 3 deletions src/Compiler/Checking/AttributeChecking.fs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ type AttribInfo =
match x with
| FSAttribInfo(_g, Attrib(tcref, _, _, _, _, _, _)) -> tcref
| ILAttribInfo (g, amap, scoref, a, m) ->
let ty = RescopeAndImportILType scoref amap m [] a.Method.DeclaringType
// We are skipping nullness check here because this reference is an attribute usage, nullness does not apply.
let ty = RescopeAndImportILTypeSkipNullness scoref amap m [] a.Method.DeclaringType
tcrefOfAppTy g ty

member x.ConstructorArguments =
Expand All @@ -104,7 +105,8 @@ type AttribInfo =
| ILAttribInfo (_g, amap, scoref, cattr, m) ->
let parms, _args = decodeILAttribData cattr
[ for argTy, arg in Seq.zip cattr.Method.FormalArgTypes parms ->
let ty = RescopeAndImportILType scoref amap m [] argTy
// We are skipping nullness check here because this reference is an attribute usage, nullness does not apply.
let ty = RescopeAndImportILTypeSkipNullness scoref amap m [] argTy
let obj = evalILAttribElem arg
ty, obj ]

Expand All @@ -119,7 +121,8 @@ type AttribInfo =
| ILAttribInfo (_g, amap, scoref, cattr, m) ->
let _parms, namedArgs = decodeILAttribData cattr
[ for nm, argTy, isProp, arg in namedArgs ->
let ty = RescopeAndImportILType scoref amap m [] argTy
// We are skipping nullness check here because this reference is an attribute usage, nullness does not apply.
let ty = RescopeAndImportILTypeSkipNullness scoref amap m [] argTy
let obj = evalILAttribElem arg
let isField = not isProp
ty, nm, isField, obj ]
Expand Down
18 changes: 10 additions & 8 deletions src/Compiler/Checking/CheckDeclarations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4708,14 +4708,16 @@ module TcDeclarations =
MutRecBindingChecking.TcMutRecDefns_UpdateModuleContents mutRecNSInfo mutRecDefnsAfterVals

// Generate the union augmentation values for all tycons.
(envMutRec, mutRecDefnsAfterCore) ||> MutRecShapes.iterTyconsWithEnv (fun envForDecls ((tyconCore, _, _), tyconOpt, _, _, _) ->
let (MutRecDefnsPhase1DataForTycon (isAtOriginalTyconDefn=isAtOriginalTyconDefn)) = tyconCore
match tyconOpt with
| Some tycon when isAtOriginalTyconDefn ->
if tycon.IsUnionTycon && AddAugmentationDeclarations.ShouldAugmentUnion cenv.g tycon then
let vspecs = AddAugmentationDeclarations.AddUnionAugmentationValues cenv envForDecls tycon
ignore vspecs
| _ -> ())
// TODO nullness :: this is the handling of DU .Is* properties WITHIN signature files.
// Watch https://github.com/fsharp/fslang-design/discussions
//(envMutRec, mutRecDefnsAfterCore) ||> MutRecShapes.iterTyconsWithEnv (fun envForDecls ((tyconCore, _, _), tyconOpt, _, _, _) ->
// let (MutRecDefnsPhase1DataForTycon (isAtOriginalTyconDefn=isAtOriginalTyconDefn)) = tyconCore
// match tyconOpt with
// | Some tycon when isAtOriginalTyconDefn ->
// if tycon.IsUnionTycon && AddAugmentationDeclarations.ShouldAugmentUnion cenv.g tycon then
// let vspecs = AddAugmentationDeclarations.AddUnionAugmentationValues cenv envForDecls tycon
// ignore vspecs
// | _ -> ())

envMutRec

Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Checking/InfoReader.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1142,7 +1142,7 @@ let GetXmlDocSigOfMethInfo (infoReader: InfoReader) m (minfo: MethInfo) =
match TryFindMetadataInfoOfExternalEntityRef infoReader m ilminfo.DeclaringTyconRef with
| None -> None
| Some (ccuFileName, formalTypars, formalTypeInfo) ->
let filminfo = ILMethInfo(g, formalTypeInfo.ToType, None, ilminfo.RawMetadata, fmtps)
let filminfo = ILMethInfo(g, IlType formalTypeInfo, ilminfo.RawMetadata, fmtps)
let args =
if ilminfo.IsILExtensionMethod then
filminfo.GetRawArgTypes(amap, m, minfo.FormalMethodInst)
Expand Down
10 changes: 5 additions & 5 deletions src/Compiler/Checking/NicePrint.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1646,14 +1646,14 @@ module InfoMemberPrinting =

// Prettify an ILMethInfo
let prettifyILMethInfo (amap: Import.ImportMap) m (minfo: MethInfo) typarInst ilMethInfo =
let (ILMethInfo(_, apparentTy, dty, mdef, _)) = ilMethInfo
let (prettyTyparInst, prettyTys), _ = PrettyTypes.PrettifyInstAndTypes amap.g (typarInst, (apparentTy :: minfo.FormalMethodInst))
let (ILMethInfo(_, methodsType, mdef, _)) = ilMethInfo
let (prettyTyparInst, prettyTys), _ = PrettyTypes.PrettifyInstAndTypes amap.g (typarInst, (methodsType.ToType :: minfo.FormalMethodInst))
match prettyTys with
| prettyApparentTy :: prettyFormalMethInst ->
let prettyMethInfo =
match dty with
| None -> MethInfo.CreateILMeth (amap, m, prettyApparentTy, mdef)
| Some declaringTyconRef -> MethInfo.CreateILExtensionMeth(amap, m, prettyApparentTy, declaringTyconRef, minfo.ExtensionMemberPriorityOption, mdef)
match methodsType with
| IlType _ -> MethInfo.CreateILMeth (amap, m, prettyApparentTy, mdef)
| CSharpStyleExtension(declaring=declaringTyconRef) -> MethInfo.CreateILExtensionMeth(amap, m, prettyApparentTy, declaringTyconRef, minfo.ExtensionMemberPriorityOption, mdef)
prettyTyparInst, prettyMethInfo, prettyFormalMethInst
| _ -> failwith "prettifyILMethInfo - prettyTys empty"

Expand Down
31 changes: 19 additions & 12 deletions src/Compiler/Checking/TypeHierarchy.fs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ let GetSuperTypeOfType g amap m ty =
let tinst = argsOfAppTy g ty
match tdef.Extends with
| None -> None
| Some ilTy -> Some (RescopeAndImportILType scoref amap m tinst ilTy)
// 'inherit' cannot refer to a nullable type
| Some ilTy -> Some (RescopeAndImportILTypeSkipNullness scoref amap m tinst ilTy)

| FSharpOrArrayOrByrefOrTupleOrExnTypeMetadata ->
if isFSharpObjModelTy g ty || isFSharpExceptionTy g ty then
Expand Down Expand Up @@ -115,7 +116,8 @@ let GetImmediateInterfacesOfMetadataType g amap m skipUnref ty (tcref: TyconRef)
// assume those are present.
for intfTy in tdef.Implements do
if skipUnref = SkipUnrefInterfaces.No || CanRescopeAndImportILType scoref amap m intfTy then
RescopeAndImportILType scoref amap m tinst intfTy
// Implementing an interface cannot refer to a nullable type
RescopeAndImportILTypeSkipNullness scoref amap m tinst intfTy
| FSharpOrArrayOrByrefOrTupleOrExnTypeMetadata ->
for intfTy in tcref.ImmediateInterfaceTypesOfFSharpTycon do
instType (mkInstForAppTy g ty) intfTy ]
Expand Down Expand Up @@ -356,33 +358,38 @@ let ExistsHeadTypeInEntireHierarchy g amap m typeToSearchFrom tcrefToLookFor =
ExistsInEntireHierarchyOfType (HasHeadType g tcrefToLookFor) g amap m AllowMultiIntfInstantiations.Yes typeToSearchFrom

/// Read an Abstract IL type from metadata and convert to an F# type.
let ImportILTypeFromMetadata amap m scoref tinst minst ilTy =
RescopeAndImportILType scoref amap m (tinst@minst) ilTy
let ImportILTypeFromMetadata amap m scoref tinst minst nullnessSource ilTy =
RescopeAndImportILType scoref amap m (tinst@minst) nullnessSource ilTy

/// Read an Abstract IL type from metadata and convert to an F# type, ignoring nullness checking.
let ImportILTypeFromMetadataSkipNullness amap m scoref tinst minst ilTy =
RescopeAndImportILTypeSkipNullness scoref amap m (tinst@minst) ilTy

/// Read an Abstract IL type from metadata, including any attributes that may affect the type itself, and convert to an F# type.
let ImportILTypeFromMetadataWithAttributes amap m scoref tinst minst ilTy getCattrs =
let ty = RescopeAndImportILType scoref amap m (tinst@minst) ilTy
let ImportILTypeFromMetadataWithAttributes amap m scoref tinst minst nullnessSource ilTy =
let ty = RescopeAndImportILType scoref amap m (tinst@minst) nullnessSource ilTy

// If the type is a byref and one of attributes from a return or parameter has
// - a `IsReadOnlyAttribute` - it's an inref
// - a `RequiresLocationAttribute` (in which case it's a `ref readonly`) which we treat as inref,
// latter is an ad-hoc fix for https://github.com/dotnet/runtime/issues/94317.
if isByrefTy amap.g ty
&& (TryFindILAttribute amap.g.attrib_IsReadOnlyAttribute (getCattrs ())
|| TryFindILAttribute amap.g.attrib_RequiresLocationAttribute (getCattrs ())) then
&& (TryFindILAttribute amap.g.attrib_IsReadOnlyAttribute (nullnessSource.DirectAttributes.Read())
|| TryFindILAttribute amap.g.attrib_RequiresLocationAttribute (nullnessSource.DirectAttributes.Read())) then
mkInByrefTy amap.g (destByrefTy amap.g ty)
else
ty

/// Get the parameter type of an IL method.
let ImportParameterTypeFromMetadata amap m ilTy getCattrs scoref tinst mist =
ImportILTypeFromMetadataWithAttributes amap m scoref tinst mist ilTy getCattrs
let ImportParameterTypeFromMetadata amap m nullnessSource ilTy scoref tinst mist =
ImportILTypeFromMetadataWithAttributes amap m scoref tinst mist nullnessSource ilTy

/// Get the return type of an IL method, taking into account instantiations for type, return attributes and method generic parameters, and
/// translating 'void' to 'None'.
let ImportReturnTypeFromMetadata amap m ilTy getCattrs scoref tinst minst =
let ImportReturnTypeFromMetadata amap m nullnessSource ilTy scoref tinst minst =
match ilTy with
| ILType.Void -> None
| retTy -> Some(ImportILTypeFromMetadataWithAttributes amap m scoref tinst minst retTy getCattrs)
| retTy -> Some(ImportILTypeFromMetadataWithAttributes amap m scoref tinst minst nullnessSource retTy )


/// Copy constraints. If the constraint comes from a type parameter associated
Expand Down
17 changes: 14 additions & 3 deletions src/Compiler/Checking/TypeHierarchy.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,17 @@ val ExistsHeadTypeInEntireHierarchy:

/// Read an Abstract IL type from metadata and convert to an F# type.
val ImportILTypeFromMetadata:
amap: ImportMap ->
m: range ->
scoref: ILScopeRef ->
tinst: TType list ->
minst: TType list ->
nullnessSource: Nullness.NullableAttributesSource ->
ilTy: ILType ->
TType

/// Read an Abstract IL type from metadata and convert to an F# type, ignoring nullness checking.
val ImportILTypeFromMetadataSkipNullness:
amap: ImportMap -> m: range -> scoref: ILScopeRef -> tinst: TType list -> minst: TType list -> ilTy: ILType -> TType

/// Read an Abstract IL type from metadata, including any attributes that may affect the type itself, and convert to an F# type.
Expand All @@ -126,16 +137,16 @@ val ImportILTypeFromMetadataWithAttributes:
scoref: ILScopeRef ->
tinst: TType list ->
minst: TType list ->
nullnessSource: Nullness.NullableAttributesSource ->
ilTy: ILType ->
getCattrs: (unit -> ILAttributes) ->
TType

/// Get the parameter type of an IL method.
val ImportParameterTypeFromMetadata:
amap: ImportMap ->
m: range ->
nullnessSource: Nullness.NullableAttributesSource ->
ilTy: ILType ->
getCattrs: (unit -> ILAttributes) ->
scoref: ILScopeRef ->
tinst: TType list ->
mist: TType list ->
Expand All @@ -146,8 +157,8 @@ val ImportParameterTypeFromMetadata:
val ImportReturnTypeFromMetadata:
amap: ImportMap ->
m: range ->
nullnessSource: Nullness.NullableAttributesSource ->
ilTy: ILType ->
getCattrs: (unit -> ILAttributes) ->
scoref: ILScopeRef ->
tinst: TType list ->
minst: TType list ->
Expand Down
Loading

0 comments on commit d697c63

Please sign in to comment.