/* * Copyright (c) 2003-2008 The University of Wroclaw. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the University may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL THE UNIVERSITY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ using Nemerle.Compiler; using Nemerle.Compiler.SolverMacros; using Nemerle.Compiler.Typedtree; using Nemerle.Collections; using Nemerle.Utility; namespace Nemerle.Compiler { public type MemberKinds = System.Reflection.MemberTypes; public type BindingFlags = System.Reflection.BindingFlags; public enum Accessibility { | Public | Internal | ProtectedOrInternal | ProtectedAndInternal | Protected | Private } public variant BuiltinMethodKind { | NotBuiltin | OpCode { checked_opcode : string; unchecked_opcode : string; } | CallWithCast { meth : IMethod; } | ValueTypeConversion | ExtensionMethod { impl : IMethod; } } public interface IMember { GetMemType () : MType; Location : Location { get; } GetHandle () : System.Reflection.MemberInfo; CanAccess (source : TypeInfo) : bool; IsObsolete : bool { get; } IsPrivate : bool { get; } /* public properties */ DeclaringType : TypeInfo {get;} Name : string {get;} MemberKind : MemberKinds {get;} IsStatic : bool { get; } // types are always static HasBeenUsed : bool { get; set; } // for the 'unused' warnings Attributes : NemerleAttributes { get; } /* public methods */ GetModifiers () : Modifiers; } public interface IField : IMember { IsMutable : bool { get; } IsVolatile : bool { get; } IsLiteral : bool { get; } GetValue () : Literal; GetFieldInfo () : System.Reflection.FieldInfo; HasBeenAssigned : bool { get; set; } } public interface IEvent : IMember { GetEventInfo () : System.Reflection.EventInfo; GetAdder () : IMethod; GetRemover () : IMethod; } public interface IMethod : IMember { GetFreshType () : MType * list [TyVar]; Header : Fun_header { get; } GetHeader () : Fun_header; GetMethodBase () : System.Reflection.MethodBase; GetMethodInfo () : System.Reflection.MethodInfo; GetConstructorInfo () : System.Reflection.ConstructorInfo; IsVarArgs : bool { get; } IsFinal : bool { get; } IsAbstract : bool { get; } IsExtension : bool { get; } BuiltinKind : BuiltinMethodKind { get; } new GetMemType () : MType.Fun; /// Obtains list of parameters of typed method GetParameters () : list [Fun_parm]; /// Obtain return type of typed method. If it is already inferred/fixed /// the value is one of MType variant options. ReturnType : TyVar { get; } } public interface IProperty : IMember { IsIndexer : bool { get; } IsMutable : bool { get; } GetPropertyInfo () : System.Reflection.PropertyInfo; GetGetter () : IMethod; GetSetter () : IMethod; } public abstract class MemberInfo { [Accessor] protected mutable is_obsolete : bool; [Accessor] protected mutable attributes : NemerleAttributes; public virtual IsStatic : bool { get { attributes %&& NemerleAttributes.Static } } public IsPublic : bool { get { attributes %&& NemerleAttributes.Public } } public IsPrivate : bool { get { attributes %&& NemerleAttributes.Private } } public IsProtected : bool { get { attributes %&& NemerleAttributes.Protected } } public IsInternal : bool { get { attributes %&& NemerleAttributes.Internal } } public IsAbstract : bool { get { attributes %&& NemerleAttributes.Abstract } } public virtual HasBeenUsed : bool { // for the 'unused' warnings get { true; } // default impl set { when (is_obsolete && value) { // value indicates if we should warn about obsolete mutable msg, is_error; (msg, is_error) = GetObsoletionDetails (); if (msg == null) msg = $"$this is obsolete"; else msg = $"$this is obsolete: '$msg'"; if (is_error) Message.Error (msg); else Message.Warning (618, msg); } } } public abstract GetModifiers () : Modifiers; public abstract GlobalEnv : GlobalEnv { get; } internal virtual GetObsoletionDetails () : string * bool { def obsoletion_tc = this.GlobalEnv.Manager.InternalType.Obsolete_tc; def mods = GetModifiers (); assert (mods != null, this.ToString ()); def (_, parms) = mods.FindAttributeWithArgs (obsoletion_tc, this.GlobalEnv).Value; mutable msg = null, is_error = false; foreach (x in parms) { | <[ $(m : string) ]> => msg = m; | <[ $(b : bool) ]> => is_error = b; | <[ Message = $(m : string) ]> => msg = m; | <[ IsError = $(b : bool) ]> => is_error = b; | _ => () } (msg, is_error) } } [ManagerAccess] public abstract class TypeInfo : MemberInfo, IMember, System.IComparable [TypeInfo] { [Accessor] protected mutable system_type : System.Type; id : int; protected mutable default_indexer : string; protected internal mutable typarms : list [StaticTyVar] = []; protected mutable self_type : MType.Class; protected fullname : string; protected mutable member_map : Hashtable [string, list [IMember]]; protected extension_patterns : Hashtable [string, ExtensionPattern] = Hashtable (); protected namespace_nd : NamespaceTree.Node; public this (ns_node : NamespaceTree.Node, man : ManagerClass, fullname : string) { Manager = man; id = Util.next_id (man); namespace_nd = ns_node; this.fullname = fullname; } public NamespaceNode : NamespaceTree.Node { get { namespace_nd } } protected add_member_by_name (m : IMember) : void { def n = m.Name; member_map [n] = if (member_map.Contains (n)) m :: member_map [n] else [m]; } public AddExtensionPattern (e : ExtensionPattern) : void { if (GetExtensionPattern (e.Name).IsSome) Message.Error ($ "the extension pattern `$(e.Name)' is already defined on $this (or its supertype)"); else extension_patterns [e.Name] = e; } public GetExtensionPattern (name : string) : option [ExtensionPattern] { match (extension_patterns.Get (name)) { | None => match (SuperClass ()) { | Some (tc) => tc.GetExtensionPattern (name) | None => None () } | x => x } } #region Builtins protected mutable special_members : Hashtable [string, list [IMember]]; protected MakeSingleParm (name : string) : void { match (special_members [name]) { | [elem is IMethod] => def hd = elem.GetHeader (); hd.parms = List.Tl (hd.parms); | _ => assert (false) } } protected FixupCompare (name : string) : void { match (special_members [name]) { | [elem is IMethod] => def hd = elem.GetHeader (); assert (InternalType.Boolean != null); hd.ret_type = InternalType.Boolean; | _ => assert (false) } } protected ForceIntType (name : string) : void { match (special_members [name]) { | [elem is IMethod] => assert (InternalType.Int32 != null); def hd = elem.GetHeader (); hd.ret_type = InternalType.Int32; | _ => assert (false) } } protected AddConversion (name : string, target : TypeInfo) : void { AddConversion (name, target, reverse = false) } protected AddConversion (name : string, target : TypeInfo, reverse : bool) : void { def sm = BuiltinMethod (this, name, GetMemType (), BuiltinMethodKind.ValueTypeConversion ()); special_members [name] = if (special_members.Contains (name)) sm :: special_members [name] else [sm]; def hd = sm.GetHeader (); hd.parms = List.Tl (hd.parms); if (reverse) { List.Hd (hd.parms).ty = MType.Class (target, []); hd.ret_type = self_type; } else { hd.ret_type = MType.Class (target, []); } } protected AddBuiltin (name : string, opcode : string) : void { def sm = BuiltinMethod (this, name, GetMemType (), BuiltinMethodKind.OpCode (opcode, opcode)); special_members [name] = [sm : IMember]; } protected AddBuiltin (name : string, op1 : string, op2 : string) : void { def sm = BuiltinMethod (this, name, GetMemType (), BuiltinMethodKind.OpCode (op1, op2)); special_members [name] = [sm : IMember]; } protected AddBuiltin (name : string, meth : IMethod) : void { def sm = BuiltinMethod (this, name, GetMemType (), BuiltinMethodKind.CallWithCast (meth)); special_members [name] = [sm : IMember]; } protected InitBuiltinMembers () : void { when (special_members == null) { special_members = Hashtable (); if (IsValueType) match (SuperClass ()) { | Some (tc) when // InternalType is not initialized sometimes (InternalType.Enum_tc != null && tc.Equals (InternalType.Enum_tc)) || tc.FullName == "System.Enum" => AddBuiltin ("op_BitwiseOr", "|.u"); AddBuiltin ("op_BitwiseAnd", "&.u"); AddBuiltin ("op_ExclusiveOr", "^.u"); AddBuiltin ("op_OnesComplement", "unary.~.u"); MakeSingleParm ("op_OnesComplement"); AddBuiltin ("op_Equality", "=="); AddBuiltin ("op_Inequality", "!="); FixupCompare ("op_Equality"); FixupCompare ("op_Inequality"); def numeric_types = ["SByte", "Int16", "Int32", "Int64", "Byte", "UInt16", "UInt32", "UInt64"]; foreach (target in numeric_types) { def t = Manager.NameTree.LookupInternalType (["System", target]); AddConversion ("op_Explicit", t, reverse = true); AddConversion ("op_Explicit", t, reverse = false); } | _ => {} } else if (IsDelegate) { assert (InternalType.Delegate_Combine != null); assert (InternalType.Delegate_Remove != null); AddBuiltin ("op_Addition", InternalType.Delegate_Combine); AddBuiltin ("op_Subtraction", InternalType.Delegate_Remove); } else {} } } #endregion public GetHandle () : System.Reflection.MemberInfo { system_type } public override GetHashCode () : int { id } /** Compare types for equality. */ public Equals (the_other : TypeInfo) : bool { the_other != null && id == the_other.id } [Nemerle.OverrideObjectEquals] public Equals (t : IMember) : bool { id == t.GetHashCode () } public CompareTo (other : TypeInfo) : int { id - other.id } public override ToString () : string { FullName } /** Returns custom attribute targets valid for this custom attribute. Valid only for type representing custom attribute. */ public abstract AttributeTargets : System.AttributeTargets { get; } /** Types are always static */ public override IsStatic : bool { get { true } } public IsModule : bool { get { attributes %&& NemerleAttributes.Static } } public IsSealed : bool { get { attributes %&& NemerleAttributes.Sealed } } /** Specifies if given type is an interface */ public abstract IsInterface : bool { get; } internal virtual GetLibraryReference () : LibraryReference { null } public DefaultIndexerName : string { get { when (default_indexer == null) match (SuperClass ()) { | Some (tc) => default_indexer = tc.DefaultIndexerName; | None => () }; default_indexer } } /** Return full qualified type name with namespaces and nesting types, all .-separated. */ public FullName : string { get { fullname } } /** Return full qualified type name with namespaces (.-separated) and nesting types (+-separated). */ public FrameworkTypeName : string { get { def par = DeclaringType; if (par == null) FullName else par.FrameworkTypeName + "+" + Name } } public abstract LookupMemberImpl (name : string) : list [IMember]; public virtual LookupMemberAvailable : bool { get { true } } GetSignature (mem : IMember) : option [MType] { match (mem.MemberKind) { | Property when (mem :> IProperty).IsIndexer | Constructor | Method => // FIXME: this won't work for generic methods match (GetMemType ().TypeOfMember (mem).Fix ()) { | MType.Fun (from, _) => Some (from.Fix ()) | _ => None () } | _ => None () } } static Hides (e1 : IMember * option [MType], e2 : IMember * option [MType]) : bool { def s1 = e1 [1]; def s2 = e2 [1]; if (s1.IsNone || s2.IsNone) true else if (s1.Equals (s2)) { match (e1 [0].Name) { | "apply" | "apply_void" => if (e1 [0] is IMethod && e2 [0] is IMethod) (e1 [0] :> IMethod).GetParameters ().Length == (e2 [0] :> IMethod).GetParameters ().Length else true | _ => true } } else false } internal RemoveHiddenMembers (members : list [list [IMember]]) : list [IMember] { def ht = Hashtable (); mutable res = []; foreach (mems in members.Rev ()) foreach (origelem in mems) { def name = origelem.Name; def elem = (origelem, GetSignature (origelem)); if (ht.Contains (name)) { // wtf? the enf unless ((ht [name] : list [_]).Exists (fun (oldelem) { Hides (elem, oldelem) })) { ht [name] ::= elem; res ::= origelem; } } else { ht [name] = [elem]; res ::= origelem; } } //Message.Debug ($ "rhm: $members -> $res"); res.Rev () } RemoveHiddenMembersSingleName (members : list [list [IMember]]) : list [IMember] { mutable store = []; mutable res = []; foreach (mems in members.Rev ()) foreach (origelem in mems) { def elem = (origelem, GetSignature (origelem)); unless (store.Exists (fun (oldelem) { Hides (elem, oldelem) })) { res ::= origelem; store ::= elem; } } res.Rev () } /** Look for specified member. Semantics of returning base class member is the same as for [System.Type.GetMember] method. */ public LookupMember (name : string, for_completion = false) : list [IMember] { when (special_members == null) InitBuiltinMembers (); if (for_completion) GetMembers ().Filter (fun (mem) { mem.Name.StartsWith (name, System.StringComparison.InvariantCultureIgnoreCase) }) else if (special_members.Contains (name)) special_members [name] else { def loop (acc, ti : TypeInfo) { def res = ti.LookupMemberImpl (name); // filter out members with override specified // def res = res.RevFilterWhenNeeded (aint_override); def acc = if (res is []) acc else res :: acc; if (ti.IsInterface) match (ti.GetDirectSuperTypes ()) { | [] => InternalType.Object_tc.LookupMemberImpl (name) :: acc | ifaces => ifaces.Map (fun (c) { c.tycon.LookupMember (name) }) + acc } else match (ti.SuperClass ()) { | Some (ti) => loop (acc, ti) | None => acc } } if (name == ".ctor") // don't recurse LookupMemberImpl (name) else { match (loop ([], this)) { | [] => [] | [one] => one | members => // we have to protect agains members with 'new' def res = RemoveHiddenMembersSingleName (members); //Message.Debug ($ "members= $members, after removal $res"); res } } } } /** */ public abstract GetTydecl () : TypeDeclaration; // helper used in TypeInfo internal ConstructSubst (tc : TypeInfo, typarms : list [StaticTyVar], args : list [TyVar], check_parms : bool) : Subst { def res = Subst (); def messenger = Manager.Solver.CurrentMessenger; unless (typarms.IsEmpty && args.IsEmpty) { def len_tp = typarms.Length; def len_ac = args.Length; if (len_tp == len_ac) { List.Iter2 (typarms, args, fun (tp, val : TyVar) { res.Add (tp, val); }); when (check_parms) List.Iter2 (typarms, args, fun (tp : StaticTyVar, val : TyVar) { when (val.Equals (InternalType.Void)) ReportError (messenger, $ "cannot use `void' as a generic parameter of $tc"); unless (val.Require (res.Apply (tp.LowerBound))) { ReportError (messenger, $ "typing constraint on $(tp.Name) not satisfied, " "upon instantiation of $tc"); } }); } else { ReportError (messenger, $ "type `$(tc.FullName)' takes $len_tp argument(s) " "while $len_ac were supplied"); } } res } /** Construct substitution resulting from applying this type constructor to specified arguments. For example assuming our type parameters are are ('a, 'b), then [MakeSubst (t1, t2)] produces substitution { 'a := t1; 'b := t2 }. */ internal MakeSubst (parms : list [TyVar]) : Subst { ConstructSubst (this, typarms, parms, check_parms = true) } internal MakeUncheckedSubst (args : list [TyVar]) : Subst { ConstructSubst (this, typarms, args, check_parms = false) } internal MakeSubst1 (parms : list [MType]) : Subst { MakeSubst (Solver.MonoTypes (parms)) } /** * Return substitution replacing each of our type parameters with fresh * type variable. */ internal FreshSubst () : Subst { Subst.Fresh (typarms) [0] } public virtual GetFreshType () : MType.Class { FreshSubst ().MonoApply (GetMemType ()) :> MType.Class } /** If this tycon subtypes [tycon], then return instantiation using which we subtype it. */ public abstract SuperType (tycon : TypeInfo) : option [list [MType]]; /** */ public abstract SubtypingSubst (tycon : TypeInfo) : Subst; /** [parent] is one of the enclosing types of [this]. For Parent['a,'b] and This['a1,'b1,'c] returns ['a := 'a1, 'b := 'b1]. If there are types between [parent] and [this], their type variables are also replaced. */ public virtual NestingSubst (parent : TypeInfo) : Subst { if (parent.Equals (this)) Subst () else { def res = Subst (); def cnt = parent.TyparmsCount; def target = GetMemType ().args.FirstN (cnt); def loop (ti) { def source = ti.Typarms.FirstN (cnt); List.Iter2 (source, target, res.Add); when (! ti.Equals (parent)) loop (ti.DeclaringType) } loop (DeclaringType); res } } public abstract SuperClass () : option [TypeInfo]; /** Gets the direct base type of this type. Null if there isn't any (e.g. for interfaces) */ public abstract BaseType : TypeInfo { get; } /** Return list of all members defined in this very type and its supertypes. */ public abstract GetMembers () : list [IMember]; /** Searches for the members defined for the current TypeInfo, using the specified binding constraints. */ public abstract GetMembers (bindingAttr : BindingFlags) : list [IMember]; /** Searches for the fields defined for the current TypeInfo, using the specified binding constraints. */ public abstract GetFields (bindingAttr : BindingFlags) : list [IField]; public abstract GetConstructors (bindingAttr : BindingFlags) : list [IMethod]; /** */ public abstract GetSuperTypes () : list [MType.Class]; public abstract GetDirectSuperTypes () : list [MType.Class]; /** If this is a constant variant option, this method returns static class member that shall be used instead of calling constructor. Otherwise [null] is returned. */ public abstract GetConstantObject () : IField; public abstract IsDelegate : bool { get; } public virtual IsEnum : bool { get { assert (InternalType.Enum_tc != null); IsValueType && match (SuperClass ()) { | Some (tc) => tc.Equals (InternalType.Enum_tc) | None => false } } } public abstract Accessibility : Accessibility { get; } /** * True if the type will be accessible from an external assembly. * This depends on this type's and parent types' accessibility. */ public abstract IsExternallyAccessible : bool { get; } /** If this is constructor of value type (which is allocated on stack not on heap) */ public abstract IsValueType : bool { get;} public abstract HasAttribute (attribute : TypeInfo) : bool; /** * If this type was defined as [class Foo ('a, 'b) { ... }] then return * type expression [Foo ('a, 'b)]. * * Used mainly with [FreshSubst ()] or [MakeSubst ()]. */ public GetMemType () : MType.Class { assert (self_type != null, FullName); self_type } public virtual TyparmsCount : int { get { typarms.Length } } public virtual SourceTyparmsCount : int { get { if (DeclaringType == null) TyparmsCount else TyparmsCount - DeclaringType.TyparmsCount } } public virtual Typarms : list [StaticTyVar] { get { typarms } } public abstract Location : Location { get; } public abstract CanAccess (source : TypeInfo) : bool; /* public properties */ public abstract DeclaringType : TypeInfo { get; } public abstract Name : string { get; } public virtual MemberKind : MemberKinds { get { if (DeclaringType != null) MemberKinds.NestedType else MemberKinds.TypeInfo } } public abstract UnderlyingType : TypeInfo { get; } } } // ns