public bool CheckInvariantMeaningInBlock (string name, Expression e, Location loc) { Block b = this; IKnownVariable kvi = b.Explicit.GetKnownVariable (name); while (kvi == null) { b = b.Explicit.Parent; if (b == null) return true; kvi = b.Explicit.GetKnownVariable (name); } if (kvi.Block == b) return true; // Is kvi.Block nested inside 'b' if (b.Explicit != kvi.Block.Explicit) { // // If a variable by the same name it defined in a nested block of this // block, we violate the invariant meaning in a block. // if (b == this) { Toplevel.Report.SymbolRelatedToPreviousError (kvi.Location, name); Toplevel.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", name); return false; } // // It's ok if the definition is in a nested subblock of b, but not // nested inside this block -- a definition in a sibling block // should not affect us. // return true; } // // Block 'b' and kvi.Block are the same textual block. // However, different variables are extant. // // Check if the variable is in scope in both blocks. We use // an indirect check that depends on AddVariable doing its // part in maintaining the invariant-meaning-in-block property. // if (e is VariableReference || (e is Constant && b.GetLocalInfo (name) != null)) return true; if (this is ToplevelBlock) { Toplevel.Report.SymbolRelatedToPreviousError (kvi.Location, name); e.Error_VariableIsUsedBeforeItIsDeclared (Toplevel.Report, name); return false; } // // Even though we detected the error when the name is used, we // treat it as if the variable declaration was in error. // Toplevel.Report.SymbolRelatedToPreviousError (loc, name); Error_AlreadyDeclared (kvi.Location, name, "parent or current"); return false; }