Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

$BlockedFromReflection instead of name of type #5951

Closed
FoggyFinder opened this issue Jun 16, 2018 · 8 comments
Closed

$BlockedFromReflection instead of name of type #5951

FoggyFinder opened this issue Jun 16, 2018 · 8 comments

Comments

@FoggyFinder
Copy link

FoggyFinder commented Jun 16, 2018

When I try to do the follow (name for type of some type):

var tp = typeof(Int32).GetType();
Console.WriteLine("Name = {0}", tp.Name); 

I get the next result:

Name = $BlockedFromReflection_0_0dc86273

I guess it has to be RuntimeType (at least this result I get when run via dotnet run)


I found the #5838 perhaps it's related.

@zpodlovics
Copy link

zpodlovics commented Jun 16, 2018

Also related:
#3810 and b8ec0ab

@MichalStrehovsky
Copy link
Member

What's the scenario where the F# tests need this? You're getting BlockedFromReflection because this is trying to reflect on an internal implementation detail of the runtime (trying to reflect on the System.Type instance that the typeof operator generated). These things vary from runtime to runtime and from a specific version of a runtime to a specific version of the runtime. It's very fragile.

(On CoreRT, this is going to actually give you NativeFormatRuntimeNamedTypeInfo, not RuntimeType...)

MichalStrehovsky added a commit to MichalStrehovsky/corert that referenced this issue Jun 18, 2018
This adds a compiler option to disable the behavior that blocks metadata generation for framework implementation details.

Enabling the option regresses the size of a Hello world app from 3,891,200 bytes to 5,970,432. We don't want to enable this by default because normal apps have no business in reflecting on the implementation details of the framework. Implementation details vary from version to version and from runtime to runtime.

This is likely going to be needed for dotnet#5838 (the CoreFX tests try to access implementation details to test these - we did the work to disable any such tests on UAPAOT, but that's not the flavor of tests we run in CoreRT repo). Fixes dotnet#5951.
@zpodlovics
Copy link

@MichalStrehovsky

The F# testsuite is full of typeof and typedefof operations, even the most basic core test functionality will require it. F# have own metadata for storing details for discriminated union, currying and other things and an internal reflection like mechanism to expose this metadata to the compiler and the developers:

https://github.com/Microsoft/visualfsharp/blob/master/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs

F# metadata reflection mechanism (eg.: for discriminated union types, records):

https://github.com/Microsoft/visualfsharp/blob/master/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Reflection/FSharpReflection.fs
https://github.com/Microsoft/visualfsharp/blob/master/tests/fsharp/core/reflect/test2.fs

Attributes tests:
https://github.com/Microsoft/visualfsharp/blob/master/tests/fsharp/core/attributes/test.fsx

A "bit" more complex example for type providers:
https://github.com/Microsoft/visualfsharp/blob/master/tests/fsharp/typeProviders/helloWorld/provider.fsx

@MichalStrehovsky
Copy link
Member

MichalStrehovsky commented Jun 18, 2018

I don't really know F# and can't quickly skim these files. Can you point me to the lines that do this kind of things: typeof(Int32).GetType()?

I would get if they do this:

var tp = typeof(Int32);
Console.WriteLine("Name = {0}", tp.Name); 

This will print Int32 on any runtime.

What I don't get is why they reflect on the implementation details of the reflection stack:

var tp = typeof(Int32).GetType();
Console.WriteLine("Name = {0}", tp.Name); 

This will print the name of the internal implementation type that reflection uses to represent runtime types (i.e. you're no longer reflecting on Int32, you're reflecting on the reflection stack itself). It will print the same thing no matter what the original typeof was (i.e. typeof(int).GetType() == typeof(double).GetType() == typeof(single).GetType()).

@zpodlovics
Copy link

Quick and Dirty grep output for "GetType()" calls within the testsuite, I hope it will help:
FSharpTestsGetType.txt

Quick and Dirty grep output for "GetType()" calls within the src, I hope it will help:
FSharpSrcGetType.txt

@MichalStrehovsky
Copy link
Member

Quick and Dirty grep output for "GetType()" calls within the testsuite, I hope it will help:

I saw those. But those are doing things like Assert.AreEqual(typeof<uint64>, resultValue.GetType()). Those make total sense. They compare the type information of some public framework type to the type information retrieved by calling Object.GetType() on an expected instance of that type. This is documented and portable.

What I don't understand is the use case of typeof(X).GetType(). This is the moral equivalent of resultValue.GetType().GetType() and that's the thing I want to understand (you already have a System.Type but then you reflect on the System.Type to get another System.Type).

@zpodlovics
Copy link

zpodlovics commented Jun 18, 2018

Oh I see. typeof<'T> in fsharp is an operator in F#:
https://github.com/Microsoft/visualfsharp/blob/master/src/fsharp/FSharp.Core/prim-types.fs#L448

As F# always generalizes the functions to operate as widely as possible on multiple types. The 'T (X in your example) may not yet know by the developer, but will be solved (statically) by the compiler with type inference during the compilation. Yes the typeof<'T> it could be assigned to a local variable, but it seems the typical usage is almost exclusively to use directly.

Match directly on types:
https://github.com/Microsoft/visualfsharp/blob/master/src/fsharp/FSharp.Core/prim-types.fs#L2116

Assert:
https://github.com/Microsoft/visualfsharp/blob/master/src/absil/illib.fs#L304

Also lot's of the time there will no resultsValue in a function the as the result itself will be one or more function constructed based on these typeof:

Type based metaprogramming and / or specialization like this (if you define a type in F#, the compiler will automatically generate for you a more or less specialized equality functionality):

https://github.com/Microsoft/visualfsharp/blob/70dee190c8f393dd5fc4652754423c70f746f70b/src/fsharp/FSharp.Core/prim-types.fs#L2086

@FoggyFinder
Copy link
Author

What's the scenario where the F# tests need this? You're getting BlockedFromReflection because this is trying to reflect on an internal implementation detail of the runtime (trying to reflect on the System.Type instance that the typeof operator generated). These things vary from runtime to runtime and from a specific version of a runtime to a specific version of the runtime. It's very fragile.

Thank you for the answer. It was general Q. I didn't find any information why it has such behaviour - that's why I opened issue.

MichalStrehovsky added a commit that referenced this issue Jun 18, 2018
This adds a compiler option to disable the behavior that blocks metadata generation for framework implementation details.

Enabling the option regresses the size of a Hello world app from 3,891,200 bytes to 5,970,432. We don't want to enable this by default because normal apps have no business in reflecting on the implementation details of the framework. Implementation details vary from version to version and from runtime to runtime.

This is likely going to be needed for #5838 (the CoreFX tests try to access implementation details to test these - we did the work to disable any such tests on UAPAOT, but that's not the flavor of tests we run in CoreRT repo). Fixes #5951.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants