private void CheckMatchingMethodForConsistency(MethodInfo matchingMethod, FunctionObject func, int i, int n){ // return-type consistency - the return-type has to be the same IReflect rir = func.ReturnType(null); IReflect mrir = matchingMethod is JSFieldMethod ? ((JSFieldMethod)matchingMethod).func.ReturnType(null) : matchingMethod.ReturnType; if (!rir.Equals(mrir)){ func.funcContext.HandleError(JSError.DifferentReturnTypeFromBase, func.name, true); return; } //Special treatment for methods that implement interface methods if (func.implementedIface != null){ func.implementedIfaceMethod = matchingMethod; this.superMembers[i] = func.name; //obliterate it so that it does not show up as unimplemented return; } // visibility consistency - the visibility specification has to be the same MethodAttributes visibility = func.attributes & MethodAttributes.MemberAccessMask; if ((matchingMethod.Attributes & MethodAttributes.MemberAccessMask) != visibility) //Allow Family to match FamORAssem if ((matchingMethod.Attributes & MethodAttributes.MemberAccessMask) != MethodAttributes.FamORAssem || visibility != MethodAttributes.Family) func.funcContext.HandleError(JSError.CannotChangeVisibility); // hiding, overriding and layout consistency // if i >= 0 after this, the base method is an overridden abstract method and steps should be taken to prevent a not implemented error if (func.noVersionSafeAttributeSpecified){ // current method does not specify any attribute (i.e. hide or override) if (this.Engine.versionSafe){ //Give a message. The compiler option requires a method to say hide or override when there is a match. if ((matchingMethod.Attributes & MethodAttributes.Abstract) != 0){ // base is abstract func.funcContext.HandleError(JSError.HidesAbstractInBase, this.name + "." + func.name); func.attributes &= ~MethodAttributes.NewSlot; //Recover from error by overriding, it may be less bad than throwing a class load exception }else{ func.funcContext.HandleError(JSError.NewNotSpecifiedInMethodDeclaration, this.IsInTheSameCompilationUnit(matchingMethod)); i = -1; } }else{ //No message, override if possible, otherwise hide if ((matchingMethod.Attributes & MethodAttributes.Virtual) == 0 || (matchingMethod.Attributes & MethodAttributes.Final) != 0){ // base is non virtual or final, hide i = -1; }else{ func.attributes &= ~MethodAttributes.NewSlot; //override if ((matchingMethod.Attributes & MethodAttributes.Abstract) == 0) i = -1; } } }else{ //Current method is marked override or hide if ((func.attributes & MethodAttributes.VtableLayoutMask) == MethodAttributes.ReuseSlot){ // current method specifies override if ((matchingMethod.Attributes & MethodAttributes.Virtual) == 0 || (matchingMethod.Attributes & MethodAttributes.Final) != 0){ // base is non virtual or final, hide func.funcContext.HandleError(JSError.MethodInBaseIsNotVirtual); i = -1; }else{ func.attributes &= ~MethodAttributes.NewSlot; //override if ((matchingMethod.Attributes & MethodAttributes.Abstract) == 0) i = -1; } }else{ // current method specifies hide Debug.Assert((func.attributes & MethodAttributes.VtableLayoutMask) == MethodAttributes.NewSlot); if ((matchingMethod.Attributes & MethodAttributes.Abstract) != 0){ // base is abstract func.funcContext.HandleError(JSError.HidesAbstractInBase, this.name + "." + func.name); func.attributes &= ~MethodAttributes.NewSlot; //Recover from error by overriding, it may be less bad than throwing a class load exception }else i = -1; } } if (i >= 0){ //Overriding an abstract method. Take steps to prevent error messages. Debug.Assert((matchingMethod.Attributes & MethodAttributes.Abstract) != 0); this.superMembers[i] = func.name; //obliterate it so that it does not show up as unimplemented //Do likewise for any matching abstract members declared in less derived base classes for (int j = i+1; j < n; j++){ //Most derived class is always first MemberInfo mem = this.superMembers[j] as MemberInfo; if (mem == null) continue; if (mem.Name != matchingMethod.Name) break; MethodInfo meth2 = mem as MethodInfo; if (meth2 == null) continue; if (meth2.IsAbstract && Class.ParametersMatch(meth2.GetParameters(), matchingMethod.GetParameters())){ IReflect rt = matchingMethod is JSFieldMethod ? ((JSFieldMethod)matchingMethod).ReturnIR() : matchingMethod.ReturnType; IReflect rt2 = meth2 is JSFieldMethod ? ((JSFieldMethod)meth2).ReturnIR() : meth2.ReturnType; if (rt == rt2) this.superMembers[j] = func.name; } } } }