Exemple #1
0
        private static TypeSymbol NarrowTypeInternal(ITypeManager typeManager,
                                                     SyntaxBase expression,
                                                     TypeSymbol targetType,
                                                     IDiagnosticWriter diagnosticWriter,
                                                     TypeMismatchErrorFactory typeMismatchErrorFactory,
                                                     bool skipConstantCheck,
                                                     bool skipTypeErrors)
        {
            if (targetType is ResourceType targetResourceType)
            {
                // When assigning a resource, we're really assigning the value of the resource body.
                var narrowedBody = NarrowTypeInternal(typeManager, expression, targetResourceType.Body.Type, diagnosticWriter, typeMismatchErrorFactory, skipConstantCheck, skipTypeErrors);

                return(new ResourceType(targetResourceType.TypeReference, narrowedBody));
            }

            if (targetType is ModuleType targetModuleType)
            {
                var narrowedBody = NarrowTypeInternal(typeManager, expression, targetModuleType.Body.Type, diagnosticWriter, typeMismatchErrorFactory, skipConstantCheck, skipTypeErrors);

                return(new ModuleType(targetModuleType.Name, narrowedBody));
            }

            // TODO: The type of this expression and all subexpressions should be cached
            var expressionType = typeManager.GetTypeInfo(expression);

            // since we dynamically checked type, we need to collect the errors but only if the caller wants them
            if (skipTypeErrors == false && expressionType is ErrorType)
            {
                diagnosticWriter.WriteMultiple(expressionType.GetDiagnostics());
                return(targetType);
            }

            // basic assignability check
            if (AreTypesAssignable(expressionType, targetType) == false)
            {
                // fundamentally different types - cannot assign
                diagnosticWriter.Write(typeMismatchErrorFactory(targetType, expressionType, expression));
                return(targetType);
            }

            // object assignability check
            if (expression is ObjectSyntax objectValue && targetType is ObjectType targetObjectType)
            {
                return(NarrowObjectType(typeManager, objectValue, targetObjectType, diagnosticWriter, skipConstantCheck));
            }

            if (expression is ObjectSyntax objectDiscriminated && targetType is DiscriminatedObjectType targetDiscriminated)
            {
                return(NarrowDiscriminatedObjectType(typeManager, objectDiscriminated, targetDiscriminated, diagnosticWriter, skipConstantCheck));
            }

            // array assignability check
            if (expression is ArraySyntax arrayValue && targetType is ArrayType targetArrayType)
            {
                return(NarrowArrayAssignmentType(typeManager, arrayValue, targetArrayType, diagnosticWriter, skipConstantCheck));
            }

            if (targetType is UnionType targetUnionType)
            {
                return(UnionType.Create(targetUnionType.Members.Where(x => AreTypesAssignable(expressionType, x.Type) == true)));
            }

            return(targetType);
        }