private BoundExpression MakePropertyGetAccess( SyntaxNode syntax, BoundExpression rewrittenReceiver, PropertySymbol property, ImmutableArray<BoundExpression> rewrittenArguments, MethodSymbol getMethodOpt = null, BoundPropertyAccess oldNodeOpt = null) { if (_inExpressionLambda && rewrittenArguments.IsEmpty) { return oldNodeOpt != null ? oldNodeOpt.Update(rewrittenReceiver, property, LookupResultKind.Viable, property.Type) : new BoundPropertyAccess(syntax, rewrittenReceiver, property, LookupResultKind.Viable, property.Type); } else { var getMethod = getMethodOpt ?? property.GetOwnOrInheritedGetMethod(); Debug.Assert((object)getMethod != null); Debug.Assert(getMethod.ParameterCount == rewrittenArguments.Length); Debug.Assert(((object)getMethodOpt == null) || ReferenceEquals(getMethod, getMethodOpt)); return BoundCall.Synthesized( syntax, rewrittenReceiver, getMethod, rewrittenArguments); } }
private BoundExpression MakePropertyAccess( SyntaxNode syntax, BoundExpression rewrittenReceiverOpt, PropertySymbol propertySymbol, LookupResultKind resultKind, TypeSymbol type, bool isLeftOfAssignment, BoundPropertyAccess oldNodeOpt = null) { // check for System.Array.[Length|LongLength] on a single dimensional array, // we have a special node for such cases. if (rewrittenReceiverOpt != null && rewrittenReceiverOpt.Type.IsArray() && !isLeftOfAssignment) { var asArrayType = (ArrayTypeSymbol)rewrittenReceiverOpt.Type; if (asArrayType.IsSZArray) { // NOTE: we are not interested in potential badness of Array.Length property. // If it is bad reference compare will not succeed. if (ReferenceEquals(propertySymbol, _compilation.GetSpecialTypeMember(SpecialMember.System_Array__Length)) || !_inExpressionLambda && ReferenceEquals(propertySymbol, _compilation.GetSpecialTypeMember(SpecialMember.System_Array__LongLength))) { return new BoundArrayLength(syntax, rewrittenReceiverOpt, type); } } } if (isLeftOfAssignment && propertySymbol.RefKind == RefKind.None) { // This is a property set access. We return a BoundPropertyAccess node here. // This node will be rewritten with MakePropertyAssignment when rewriting the enclosing BoundAssignmentOperator. return oldNodeOpt != null ? oldNodeOpt.Update(rewrittenReceiverOpt, propertySymbol, resultKind, type) : new BoundPropertyAccess(syntax, rewrittenReceiverOpt, propertySymbol, resultKind, type); } else { // This is a property get access return MakePropertyGetAccess(syntax, rewrittenReceiverOpt, propertySymbol, oldNodeOpt); } }
private BoundExpression VisitPropertyAccess(BoundPropertyAccess node) { var receiver = node.PropertySymbol.IsStatic ? _bound.Null(ExpressionType) : Visit(node.ReceiverOpt); var getMethod = node.PropertySymbol.GetOwnOrInheritedGetMethod(); // COMPAT: see https://github.com/dotnet/roslyn/issues/4471 // old compiler used to insert casts like this and // there are known dependencies on this kind of tree shape. // // While the casts are semantically incorrect, the conditions // under which they are observable are extremely narrow: // We would have to deal with a generic T receiver which is actually a struct // that implements a property form an interface and // the implementation of the getter must make observable mutations to the instance. // // At this point it seems more appropriate to continue adding these casts. if (node.ReceiverOpt?.Type.IsTypeParameter() == true && !node.ReceiverOpt.Type.IsReferenceType) { receiver = this.Convert(receiver, getMethod.ReceiverType, isChecked: false); } return(ExprFactory("Property", receiver, _bound.MethodInfo(getMethod))); }
public override BoundNode VisitPropertyAccess(BoundPropertyAccess node) { _syntaxWithReceiver = node.Syntax; return(base.VisitPropertyAccess(node)); }
internal static bool AccessingAutopropertyFromConstructor(BoundPropertyAccess propertyAccess, Symbol fromMember) { return AccessingAutopropertyFromConstructor(propertyAccess.ReceiverOpt, propertyAccess.PropertySymbol, fromMember); }
public override BoundNode VisitPropertyAccess(BoundPropertyAccess node) { _syntaxWithReceiver = node.Syntax; return base.VisitPropertyAccess(node); }
private BoundExpression VisitPropertyAccess(BoundPropertyAccess node) { var receiver = node.PropertySymbol.IsStatic ? Bound.Null(ExpressionType) : Visit(node.ReceiverOpt); var getMethod = node.PropertySymbol.GetOwnOrInheritedGetMethod(); return ExprFactory("Property", receiver, Bound.MethodInfo(getMethod)); }
public override BoundNode VisitPropertyAccess(BoundPropertyAccess node) { return VisitPropertyAccess(node, isLeftOfAssignment: false); }
private BoundExpression MakePropertyGetAccess(CSharpSyntaxNode syntax, BoundExpression rewrittenReceiver, PropertySymbol property, BoundPropertyAccess oldNodeOpt) { return(MakePropertyGetAccess(syntax, rewrittenReceiver, property, ImmutableArray <BoundExpression> .Empty, null, oldNodeOpt)); }
public override BoundNode VisitPropertyAccess(BoundPropertyAccess node) { return(VisitPropertyAccess(node, isLeftOfAssignment: false)); }
public override BoundNode VisitPropertyAccess(BoundPropertyAccess node) { CheckReceiverIfField(node.ReceiverOpt); return base.VisitPropertyAccess(node); }
private BoundPropertyAccess TransformPropertyAccess(BoundPropertyAccess prop, ArrayBuilder<BoundExpression> stores, ArrayBuilder<LocalSymbol> temps) { // We need to stash away the receiver so that it does not get evaluated twice. // If the receiver is classified as a value of reference type then we can simply say // // R temp = receiver // temp.prop = temp.prop + rhs // // But if the receiver is classified as a variable of struct type then we // cannot make a copy of the value; we need to make sure that we mutate // the original receiver, not the copy. We have to generate // // ref R temp = ref receiver // temp.prop = temp.prop + rhs // // The rules of C# (in section 7.17.1) require that if you have receiver.prop // as the target of an assignment such that receiver is a value type, it must // be classified as a variable. If we've gotten this far in the rewriting, // assume that was the case. // If the property is static or if the receiver is of kind "Base" or "this", then we can just generate prop = prop + value if (prop.ReceiverOpt == null || prop.PropertySymbol.IsStatic || !CanChangeValueBetweenReads(prop.ReceiverOpt)) { return prop; } Debug.Assert(prop.ReceiverOpt.Kind != BoundKind.TypeExpression); BoundExpression rewrittenReceiver = VisitExpression(prop.ReceiverOpt); BoundAssignmentOperator assignmentToTemp; // SPEC VIOLATION: It is not very clear when receiver of constrained callvirt is dereferenced - when pushed (in lexical order), // SPEC VIOLATION: or when actual call is executed. The actual behavior seems to be implementation specific in different JITs. // SPEC VIOLATION: To not depend on that, the right thing to do here is to store the value of the variable // SPEC VIOLATION: when variable has reference type (regular temp), and store variable's location when it has a value type. (ref temp) // SPEC VIOLATION: in a case of unconstrained generic type parameter a runtime test (default(T) == null) would be needed // SPEC VIOLATION: However, for compatibility with Dev12 we will continue treating all generic type parameters, constrained or not, // SPEC VIOLATION: as value types. var variableRepresentsLocation = rewrittenReceiver.Type.IsValueType || rewrittenReceiver.Type.Kind == SymbolKind.TypeParameter; var receiverTemp = _factory.StoreToTemp(rewrittenReceiver, out assignmentToTemp, refKind: variableRepresentsLocation ? RefKind.Ref : RefKind.None); stores.Add(assignmentToTemp); temps.Add(receiverTemp.LocalSymbol); // CONSIDER: this is a temporary object that will be rewritten away before this lowering completes. // Mitigation: this will only produce short-lived garbage for compound assignments and increments/decrements of properties. return new BoundPropertyAccess(prop.Syntax, receiverTemp, prop.PropertySymbol, prop.ResultKind, prop.Type); }
public override BoundNode VisitPropertyAccess(BoundPropertyAccess node) { CheckReceiverIfField(node.ReceiverOpt); return(base.VisitPropertyAccess(node)); }
private BoundExpression MakePropertyGetAccess(SyntaxNode syntax, BoundExpression rewrittenReceiver, PropertySymbol property, BoundPropertyAccess oldNodeOpt) { return MakePropertyGetAccess(syntax, rewrittenReceiver, property, ImmutableArray<BoundExpression>.Empty, null, oldNodeOpt); }
private BoundExpression VisitPropertyAccess(BoundPropertyAccess node, bool isLeftOfAssignment) { var rewrittenReceiverOpt = VisitExpression(node.ReceiverOpt); return MakePropertyAccess(node.Syntax, rewrittenReceiverOpt, node.PropertySymbol, node.ResultKind, node.Type, isLeftOfAssignment, node); }
/// <summary> /// Generates a lowered form of the assignment operator for the given left and right sub-expressions. /// Left and right sub-expressions must be in lowered form. /// </summary> private BoundExpression MakeStaticAssignmentOperator( SyntaxNode syntax, BoundExpression rewrittenLeft, BoundExpression rewrittenRight, bool isRef, TypeSymbol type, bool used) { switch (rewrittenLeft.Kind) { case BoundKind.DynamicIndexerAccess: case BoundKind.DynamicMemberAccess: throw ExceptionUtilities.UnexpectedValue(rewrittenLeft.Kind); case BoundKind.PropertyAccess: { Debug.Assert(!isRef); BoundPropertyAccess propertyAccess = (BoundPropertyAccess)rewrittenLeft; BoundExpression rewrittenReceiver = propertyAccess.ReceiverOpt; PropertySymbol property = propertyAccess.PropertySymbol; Debug.Assert(!property.IsIndexer); return(MakePropertyAssignment( syntax, rewrittenReceiver, property, ImmutableArray <BoundExpression> .Empty, default(ImmutableArray <RefKind>), false, default(ImmutableArray <int>), rewrittenRight, type, used)); } case BoundKind.IndexerAccess: { Debug.Assert(!isRef); BoundIndexerAccess indexerAccess = (BoundIndexerAccess)rewrittenLeft; BoundExpression rewrittenReceiver = indexerAccess.ReceiverOpt; ImmutableArray <BoundExpression> rewrittenArguments = indexerAccess.Arguments; PropertySymbol indexer = indexerAccess.Indexer; Debug.Assert(indexer.IsIndexer || indexer.IsIndexedProperty); return(MakePropertyAssignment( syntax, rewrittenReceiver, indexer, rewrittenArguments, indexerAccess.ArgumentRefKindsOpt, indexerAccess.Expanded, indexerAccess.ArgsToParamsOpt, rewrittenRight, type, used)); } case BoundKind.Local: { Debug.Assert(!isRef || ((BoundLocal)rewrittenLeft).LocalSymbol.RefKind != RefKind.None); return(new BoundAssignmentOperator( syntax, rewrittenLeft, rewrittenRight, type, isRef: isRef)); } case BoundKind.DiscardExpression: { return(EnsureNotAssignableIfUsedAsMethodReceiver(rewrittenRight)); } default: { Debug.Assert(!isRef); return(new BoundAssignmentOperator( syntax, rewrittenLeft, rewrittenRight, type)); } } }
private BoundExpression VisitPropertyAccess(BoundPropertyAccess node) { var receiver = node.PropertySymbol.IsStatic ? _bound.Null(ExpressionType) : Visit(node.ReceiverOpt); var getMethod = node.PropertySymbol.GetOwnOrInheritedGetMethod(); // COMPAT: see https://github.com/dotnet/roslyn/issues/4471 // old compiler used to insert casts like this and // there are known dependencies on this kind of tree shape. // // While the casts are semantically incorrect, the conditions // under which they are observable are extremely narrow: // We would have to deal with a generic T receiver which is actually a struct // that implements a property form an interface and // the implementation of the getter must make observable mutations to the instance. // // At this point it seems more appropriate to continue adding these casts. if (node.ReceiverOpt?.Type.IsTypeParameter() == true && !node.ReceiverOpt.Type.IsReferenceType) { receiver = this.Convert(receiver, getMethod.ReceiverType, isChecked: false); } return ExprFactory("Property", receiver, _bound.MethodInfo(getMethod)); }
public override BoundNode VisitPropertyAccess(BoundPropertyAccess node) { return(base.VisitPropertyAccess(node)); }
private BoundExpression VisitPropertyAccess(BoundPropertyAccess node, bool isLeftOfAssignment) { var rewrittenReceiverOpt = VisitExpression(node.ReceiverOpt); return(MakePropertyAccess(node.Syntax, rewrittenReceiverOpt, node.PropertySymbol, node.ResultKind, node.Type, isLeftOfAssignment, node)); }
/// <summary> /// Generates a lowered form of the assignment operator for the given left and right sub-expressions. /// Left and right sub-expressions must be in lowered form. /// </summary> private BoundExpression MakeStaticAssignmentOperator( SyntaxNode syntax, BoundExpression rewrittenLeft, BoundExpression rewrittenRight, bool isRef, TypeSymbol type, bool used) { switch (rewrittenLeft.Kind) { case BoundKind.DynamicIndexerAccess: case BoundKind.DynamicMemberAccess: throw ExceptionUtilities.UnexpectedValue(rewrittenLeft.Kind); case BoundKind.PropertyAccess: { Debug.Assert(!isRef); BoundPropertyAccess propertyAccess = (BoundPropertyAccess)rewrittenLeft; BoundExpression? rewrittenReceiver = propertyAccess.ReceiverOpt; PropertySymbol property = propertyAccess.PropertySymbol; Debug.Assert(!property.IsIndexer); return(MakePropertyAssignment( syntax, rewrittenReceiver, property, ImmutableArray <BoundExpression> .Empty, default(ImmutableArray <RefKind>), false, default(ImmutableArray <int>), rewrittenRight, type, used)); } case BoundKind.IndexerAccess: { Debug.Assert(!isRef); BoundIndexerAccess indexerAccess = (BoundIndexerAccess)rewrittenLeft; BoundExpression? rewrittenReceiver = indexerAccess.ReceiverOpt; ImmutableArray <BoundExpression> arguments = indexerAccess.Arguments; PropertySymbol indexer = indexerAccess.Indexer; Debug.Assert(indexer.IsIndexer || indexer.IsIndexedProperty); return(MakePropertyAssignment( syntax, rewrittenReceiver, indexer, arguments, indexerAccess.ArgumentRefKindsOpt, indexerAccess.Expanded, indexerAccess.ArgsToParamsOpt, rewrittenRight, type, used)); } case BoundKind.Local: case BoundKind.Parameter: case BoundKind.FieldAccess: { Debug.Assert(!isRef || rewrittenLeft.GetRefKind() != RefKind.None); return(new BoundAssignmentOperator( syntax, rewrittenLeft, rewrittenRight, isRef, type)); } case BoundKind.DiscardExpression: { return(rewrittenRight); } case BoundKind.Sequence: // An Index or Range pattern-based indexer, or an interpolated string handler conversion // that uses an indexer argument, produces a sequence with a nested // BoundIndexerAccess. We need to lower the final expression and produce an // update sequence var sequence = (BoundSequence)rewrittenLeft; if (sequence.Value.Kind == BoundKind.IndexerAccess) { return(sequence.Update( sequence.Locals, sequence.SideEffects, MakeStaticAssignmentOperator( syntax, sequence.Value, rewrittenRight, isRef, type, used), type)); } goto default; default: { Debug.Assert(!isRef); return(new BoundAssignmentOperator( syntax, rewrittenLeft, rewrittenRight, type)); } } }
private BoundExpression BindNamedAttributeArgument(AttributeArgumentSyntax namedArgument, NamedTypeSymbol attributeType, DiagnosticBag diagnostics) { bool wasError; LookupResultKind resultKind; Symbol namedArgumentNameSymbol = BindNamedAttributeArgumentName(namedArgument, attributeType, diagnostics, out wasError, out resultKind); ReportDiagnosticsIfObsolete(diagnostics, namedArgumentNameSymbol, namedArgument, hasBaseReceiver: false); Debug.Assert(resultKind == LookupResultKind.Viable || wasError); TypeSymbol namedArgumentType; if (wasError) { namedArgumentType = CreateErrorType(); // don't generate cascaded errors. } else { namedArgumentType = BindNamedAttributeArgumentType(namedArgument, namedArgumentNameSymbol, attributeType, diagnostics); } // BindRValue just binds the expression without doing any validation (if its a valid expression for attribute argument). // Validation is done later by AttributeExpressionVisitor BoundExpression namedArgumentValue = this.BindValue(namedArgument.Expression, diagnostics, BindValueKind.RValue); namedArgumentValue = GenerateConversionForAssignment(namedArgumentType, namedArgumentValue, diagnostics); // TODO: should we create an entry even if there are binding errors? var fieldSymbol = namedArgumentNameSymbol as FieldSymbol; IdentifierNameSyntax nameSyntax = namedArgument.NameEquals.Name; BoundExpression lvalue; if ((object)fieldSymbol != null) { var containingAssembly = fieldSymbol.ContainingAssembly as SourceAssemblySymbol; // We do not want to generate any unassigned field or unreferenced field diagnostics. containingAssembly?.NoteFieldAccess(fieldSymbol, read: true, write: true); lvalue = new BoundFieldAccess(nameSyntax, null, fieldSymbol, ConstantValue.NotAvailable, resultKind, fieldSymbol.Type); } else { var propertySymbol = namedArgumentNameSymbol as PropertySymbol; if ((object)propertySymbol != null) { lvalue = new BoundPropertyAccess(nameSyntax, null, propertySymbol, resultKind, namedArgumentType); } else { lvalue = BadExpression(nameSyntax, resultKind); } } return new BoundAssignmentOperator(namedArgument, lvalue, namedArgumentValue, namedArgumentType); }
public override BoundNode VisitPropertyAccess(BoundPropertyAccess node) { var property = node.PropertySymbol; var method = property.GetMethod; // This is only checking for ref returns, so we don't fall back to the set method. if ((object)method != null && _inExpressionLambda && method.RefKind != RefKind.None) { Error(ErrorCode.ERR_RefReturningCallInExpressionTree, node); } CheckReceiverIfField(node.ReceiverOpt); return base.VisitPropertyAccess(node); }