| File: Semantics\TypeInference\RequiredConversion.vb | Web Access |
| Project: src\roslyn\src\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj (Microsoft.CodeAnalysis.VisualBasic) |
' Licensed to the .NET Foundation under one or more agreements. ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic Friend Enum RequiredConversion ' "ConversionRequired" in Dev10 compiler '// When we do type inference, we have to unify the types supplied and infer generic parameters. '// e.g. if we have Sub f(ByVal x as T(), ByVal y as T) and invoke it with x=AnimalArray, y=Mammal, '// then we have to figure out that T should be an Animal. The way that's done: '// (1) All the requirements on T are gathered together, e.g. '// T:{Mammal+vb, Animal+arr} means '// (+vb) "T is something such that argument Mammal can be supplied to parameter T" '// (+arr) "T is something such that argument Animal() can be supplied to parameter T()" '// (2) We'll go through each candidate type to see if they work. First T=Mammal. Does it work for each requirement? '// (+vb) Yes, argument Mammal can be supplied to parameter Mammal through identity '// (+arr) Sort-of, argument Animal() can be supplied to parameter Mammal() only through narrowing '// (3) Now try the next candidate, T=Animal. Does it work for each requirement? '// (+vb) Yes, argument Mammal can be supplied to parameter Animal through widening '// (+arr) Yes, argument Animal() can be supplied to parameter Animal() through identity '// (4) At the end, we pick out the one that worked "best". In this case T=Animal worked best. '// The criteria for "best" are documented and implemented in ConversionResolution.cpp/FindDominantType. '// This enumeration contains the different kinds of requirements... '// Each requirement is that some X->Y be a conversion. Inside FindDominantType we will grade each candidate '// on whether it could satisfy that requirement with an Identity, a Widening, a Narrowing, or not at all. '// Identity: '// This restriction requires that req->candidate be an identity conversion according to the CLR. '// e.g. supplying "New List(Of Mammal)" to parameter "List(Of T)", we require that Mammal->T be identity '// e.g. supplying "New List(Of Mammal)" to a parameter "List(Of T)" we require that Mammal->T be identity '// e.g. supplying "Dim ml as ICovariant(Of Mammal) = Nothing" to a parameter "*ByRef* ICovariant(Of T)" we require that Mammal->T be identity '// (but for non-ByRef covariance see "ReferenceConversion" below.) '// Note that CLR does not include lambda->delegate, and doesn't include user-defined conversions. Identity '// Any: '// This restriction requires that req->candidate be a conversion according to VB. '// e.g. supplying "New Mammal" to parameter "T", we require that Mammal->T be a VB conversion '// It includes user-defined conversions and all the VB-specific conversions. Any '// AnyReverse: '// This restriction requires that candidate->req be a conversion according to VB. '// It might hypothetically be used for "out" parameters if VB ever gets them: '// e.g. supplying "Dim m as Mammal" to parameter "Out T" we require that T->Mammal be a VB conversion. '// But the actual reason it's included now is as be a symmetric form of AnyConversion: '// this simplifies the implementation of InvertConversionRequirement and CombineConversionRequirements AnyReverse '// AnyAndReverse: '// This restriction requires that req->candidate and candidate->hint be conversions according to VB. '// e.g. supplying "Dim m as New Mammal" to "ByRef T", we require that Mammal->T be a conversion, and also T->Mammal for the copyback. '// Again, each direction includes user-defined conversions and all the VB-specific conversions. AnyAndReverse '// ArrayElement: '// This restriction requires that req->candidate be a array element conversion. '// e.g. supplying "new Mammal(){}" to "ByVal T()", we require that Mammal->T be an array-element-conversion. '// It consists of the subset of CLR-array-element-conversions that are also allowed by VB. '// Note: ArrayElementConversion gives us array covariance, and also by enum()->underlying_integral(). ArrayElement '// Reference: '// This restriction requires that req->candidate be a reference conversion. '// e.g. supplying "Dim x as ICovariant(Of Mammal)" to "ICovariant(Of T)", we require that Mammal->T be a reference conversion. '// It consists of the subset of CLR-reference-conversions that are also allowed by VB. Reference '// ReverseReference: '// This restriction requires that candidate->req be a reference conversion. '// e.g. supplying "Dim x as IContravariant(Of Animal)" to "IContravariant(Of T)", we require that T->Animal be a reference conversion. '// Note that just because T->U is a widening reference conversion, it doesn't mean that U->T is narrowing, nor vice versa. '// Again it consists of the subset of CLR-reference-conversions that are also allowed by VB. ReverseReference '// None: '// This is not a restriction. It allows for the candidate to have any relation, even be completely unrelated, '// to the hint type. It is used as a way of feeding in candidate suggestions into the algorithm, but leaving '// them purely as suggestions, without any requirement to be satisfied. (e.g. you might add the restriction '// that there be a conversion from some literal "1L", and add the type hint "Long", so that Long can be used '// as a candidate but it's not required. This is used in computing the dominant type of an array literal.) None '// These restrictions form a partial order composed of three chains: from less strict to more strict, we have: '// [reverse chain] [None] < AnyReverse < ReverseReference < Identity '// [middle chain] None < [Any,AnyReverse] < AnyConversionAndReverse < Identity '// [forward chain] [None] < Any < ArrayElement < Reference < Identity '// '// = KEY: '// / | \ = Identity '// / | \ +r Reference '// -r | +r -r ReverseReference '// | +-any | +-any AnyConversionAndReverse '// | /|\ +arr +arr ArrayElement '// | / | \ | +any Any '// -any | +any -any AnyReverse '// \ | / none None '// \ | / '// none '// '// The routine "CombineConversionRequirements" finds the least upper bound of two elements. '// The routine "StrengthenConversionRequirementToReference" walks up the current chain to a reference conversion. '// The routine "InvertConversionRequirement" switches from reverse chain to forwards chain or vice versa, '// and asserts if given ArrayElementConversion since this has no counterparts in the reverse chain. '// These three routines are called by InferTypeArgumentsFromArgumentDirectly, as it matches an '// argument type against a parameter. '// The routine "CheckHintSatisfaction" is what actually implements the satisfaction-of-restriction check. '// '// If you make any changes to this enum or the partial order, you'll have to change all the above functions. '// They do "VSASSERT(Count==8)" to help remind you to change them, should you make any additions to this enum. Count End Enum End Namespace