diff --git a/src/compiler/WebSharper.Compiler.CSharp/ProjectReader.fs b/src/compiler/WebSharper.Compiler.CSharp/ProjectReader.fs index 2e029928..c44c6655 100644 --- a/src/compiler/WebSharper.Compiler.CSharp/ProjectReader.fs +++ b/src/compiler/WebSharper.Compiler.CSharp/ProjectReader.fs @@ -1367,7 +1367,7 @@ let transformAssembly (comp : Compilation) (config: WsConfig) (rcomp: CSharpComp // register all proxies for signature redirection for TypeWithAnnotation(_, def, annot) in allTypes do match annot.ProxyOf with - | Some p -> comp.AddProxy(def, p) + | Some p -> comp.AddProxy(def, p, annot.IsProxyInteral) | _ -> () for TypeWithAnnotation(t, d, a) in allTypes do diff --git a/src/compiler/WebSharper.Compiler.FSharp/ProjectReader.fs b/src/compiler/WebSharper.Compiler.FSharp/ProjectReader.fs index 651920ef..e69d727e 100644 --- a/src/compiler/WebSharper.Compiler.FSharp/ProjectReader.fs +++ b/src/compiler/WebSharper.Compiler.FSharp/ProjectReader.fs @@ -1346,7 +1346,7 @@ let transformAssembly (logger: LoggerBase) (comp : Compilation) assemblyName (co // register all proxies for signature redirection for (def, annot) in classAnnotations.Values do match annot.ProxyOf with - | Some p -> comp.AddProxy(def, p) + | Some p -> comp.AddProxy(def, p, annot.IsProxyInteral) | _ -> () for t in topLevelTypes do diff --git a/src/compiler/WebSharper.Compiler/AttributeReader.fs b/src/compiler/WebSharper.Compiler/AttributeReader.fs index 10875d49..6c095d4a 100644 --- a/src/compiler/WebSharper.Compiler/AttributeReader.fs +++ b/src/compiler/WebSharper.Compiler/AttributeReader.fs @@ -32,7 +32,7 @@ module M = WebSharper.Core.Metadata [] type private Attribute = | Macro of TypeDefinition * option - | Proxy of TypeDefinition * TypeDefinition[] + | Proxy of TypeDefinition * TypeDefinition[] * bool | Inline of option * dollarVars: string[] | Direct of string * dollarVars: string[] | Pure @@ -62,6 +62,7 @@ type TypeAnnotation = { ProxyOf : option ProxyExtends : list + IsProxyInteral : bool IsJavaScript : bool IsJavaScriptExport : bool IsForcedNotJavaScript : bool @@ -81,6 +82,7 @@ type TypeAnnotation = { ProxyOf = None ProxyExtends = [] + IsProxyInteral = false IsJavaScript = false IsJavaScriptExport = false IsForcedNotJavaScript = false @@ -249,7 +251,7 @@ type AttributeReader<'A>() = | Some (:? System.Array as a) -> a |> Seq.cast |> Seq.map this.GetTypeDef |> Array.ofSeq | _ -> [||] - A.Proxy (p, intfTypes) + A.Proxy (p, intfTypes, false) | "InlineAttribute" -> A.Inline (this.CtorArgOption(attr), this.DollarVars(attr)) | "DirectAttribute" -> @@ -323,6 +325,7 @@ type AttributeReader<'A>() = let mutable stub = false let mutable proxy = None let mutable proxyExt = [] + let mutable proxyInt = false let mutable prot = None for a in attrs do match this.GetAssemblyName a with @@ -341,9 +344,10 @@ type AttributeReader<'A>() = js <- Some true jse <- true | A.Stub -> stub <- true - | A.Proxy (t, i) -> + | A.Proxy (t, i, ip) -> proxy <- Some t proxyExt <- List.ofArray i + proxyInt <- ip | A.Prototype p -> prot <- Some p | A.OtherAttribute -> () | ar -> attrArr.Add ar @@ -373,13 +377,14 @@ type AttributeReader<'A>() = jse <- true if parent.OptionalFields then if not (attrArr.Contains(A.OptionalField)) then attrArr.Add A.OptionalField - attrArr |> Seq.distinct |> Seq.toArray, macros.ToArray(), name, proxy, proxyExt, isJavaScript, js = Some false, jsOpts, jse, prot, isStub, List.ofSeq reqs + attrArr |> Seq.distinct |> Seq.toArray, macros.ToArray(), name, proxy, proxyExt, proxyInt, isJavaScript, js = Some false, jsOpts, jse, prot, isStub, List.ofSeq reqs member this.GetTypeAnnot (parent: TypeAnnotation, attrs: seq<'A>) = - let attrArr, macros, name, proxyOf, proxyExt, isJavaScript, isForcedNotJavaScript, _, isJavaScriptExport, prot, isStub, reqs = this.GetAttrs (parent, attrs) + let attrArr, macros, name, proxyOf, proxyExt, proxyInt, isJavaScript, isForcedNotJavaScript, _, isJavaScriptExport, prot, isStub, reqs = this.GetAttrs (parent, attrs) { ProxyOf = proxyOf ProxyExtends = proxyExt + IsProxyInteral = proxyInt IsJavaScript = isJavaScript IsJavaScriptExport = isJavaScriptExport IsForcedNotJavaScript = isForcedNotJavaScript @@ -402,7 +407,7 @@ type AttributeReader<'A>() = } member this.GetMemberAnnot (parent: TypeAnnotation, attrs: seq<'A>) = - let attrArr, macros, name, _, _, isJavaScript, _, jsOptions, isJavaScriptExport, _, isStub, reqs = this.GetAttrs (parent, attrs) + let attrArr, macros, name, _, _, _, isJavaScript, _, jsOptions, isJavaScriptExport, _, isStub, reqs = this.GetAttrs (parent, attrs) let isEp = attrArr |> Array.contains A.SPAEntryPoint let isPure = attrArr |> Array.contains A.Pure let warning = attrArr |> Array.tryPick (function A.Warn w -> Some w | _ -> None) diff --git a/src/compiler/WebSharper.Compiler/Compilation.fs b/src/compiler/WebSharper.Compiler/Compilation.fs index ab25af00..6e9b3e3b 100644 --- a/src/compiler/WebSharper.Compiler/Compilation.fs +++ b/src/compiler/WebSharper.Compiler/Compilation.fs @@ -39,6 +39,7 @@ type Compilation(meta: Info, ?hasGraph) = let notResolvedInterfaces = Dictionary() let notResolvedClasses = Dictionary() let proxies = Dictionary() + let internalProxies = HashSet() let classes = MergedDictionary meta.Classes let interfaces = MergedDictionary meta.Interfaces @@ -384,19 +385,21 @@ type Compilation(meta: Info, ?hasGraph) = member this.ToCurrentMetadata(?ignoreErrors) = if errors.Count > 0 && not (ignoreErrors = Some true) then failwith "This compilation has errors" + let withoutInternalProxies d = + d |> Dict.filter (fun t _ -> not (internalProxies.Contains(t))) { SiteletDefinition = this.SiteletDefinition Dependencies = if hasGraph then graph.GetData() else GraphData.Empty - Interfaces = interfaces.Current + Interfaces = interfaces.Current |> withoutInternalProxies Classes = - classes.Current |> Dict.map (fun c -> + classes.Current |> withoutInternalProxies |> Dict.map (fun c -> match c.Methods with | :? MergedDictionary as m -> { c with Methods = m.Current } | _ -> c ) CustomTypes = - customTypes.Current |> Dict.filter (fun _ v -> v <> NotCustomType) + customTypes.Current |> withoutInternalProxies |> Dict.filter (fun _ v -> v <> NotCustomType) MacroEntries = macroEntries.Current Quotations = quotations.Current ResourceHashes = Dictionary() @@ -416,8 +419,14 @@ type Compilation(meta: Info, ?hasGraph) = ExtraBundles = this.AllExtraBundles } - member this.AddProxy(tProxy, tTarget) = - proxies.Add(tProxy, tTarget) + member this.AddProxy(tProxy, tTarget, isInternal) = + // if the proxy is for internal use only, drop it with a warning if a proxy for target type already exists + if isInternal && (classes.Original.ContainsKey tTarget || interfaces.Original.ContainsKey tTarget || customTypes.Original.ContainsKey tTarget) then + this.AddWarning (None, SourceWarning (sprintf "Proxy for internal proxy target type '%s' already exists, ignoring the internal proxy." tTarget.Value.FullName)) + else + proxies.Add(tProxy, tTarget) + if isInternal then + internalProxies.Add(tTarget) |> ignore member this.ResolveProxySignature (meth: Method) = if proxies.Count = 0 then meth else diff --git a/src/compiler/WebSharper.Core/Attributes.fs b/src/compiler/WebSharper.Core/Attributes.fs index 6492af7b..af7cd1bf 100644 --- a/src/compiler/WebSharper.Core/Attributes.fs +++ b/src/compiler/WebSharper.Core/Attributes.fs @@ -169,6 +169,22 @@ type ProxyAttribute private () = /// Constructs a new proxy link using a type directly and allows adding inherited interfaces. new (proxiedType: Type, interfaces: Type[]) = ProxyAttribute() +/// Declares a type to be a proxy for another type, identified directly or +/// by using an assembly-qualified name. +/// Proxy exists only for use in current project. +[] +type InternalProxyAttribute private () = + inherit A() + + /// Constructs a new proxy link using a type directly. + new (proxiedType: Type) = InternalProxyAttribute() + + /// Constructs a new proxy link using an assembly-qualified name. + new (assemblyQualifiedName: string) = InternalProxyAttribute() + + /// Constructs a new proxy link using a type directly and allows adding inherited interfaces. + new (proxiedType: Type, interfaces: Type[]) = InternalProxyAttribute() + /// Marks a server-side function to be invokable remotely from the client-side. [] type RemoteAttribute() =