@@ -6332,6 +6332,10 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
6332
6332
* resolve the alias of eponymous member.
6333
6333
*/
6334
6334
tempinst.aliasdecl = tempinst.aliasdecl.toAlias2();
6335
+
6336
+ // stop AliasAssign tuple building
6337
+ if (auto td = tempinst.aliasdecl.isTupleDeclaration())
6338
+ td.building = false ;
6335
6339
}
6336
6340
6337
6341
Laftersemantic:
@@ -6726,13 +6730,28 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc)
6726
6730
*/
6727
6731
6728
6732
const errors = global.errors;
6733
+ Dsymbol s;
6734
+
6735
+ // Try AliasSeq optimization
6736
+ if (auto ti = ds.type.isTypeInstance())
6737
+ {
6738
+ if (! ti.tempinst.findTempDecl(sc, null ))
6739
+ return errorRet ();
6740
+ if (auto tempinst = isAliasSeq(sc, ti))
6741
+ {
6742
+ s = aliasAssignInPlace(sc, tempinst, aliassym);
6743
+ if (! s)
6744
+ return errorRet ();
6745
+ goto Lsymdone;
6746
+ }
6747
+ }
6729
6748
6730
6749
/* This section is needed because Type.resolve() will:
6731
6750
* const x = 3;
6732
6751
* alias y = x;
6733
6752
* try to convert identifier x to 3.
6734
6753
*/
6735
- auto s = ds.type.toDsymbol(sc);
6754
+ s = ds.type.toDsymbol(sc);
6736
6755
if (errors != global.errors)
6737
6756
return errorRet ();
6738
6757
if (s == aliassym)
@@ -6784,6 +6803,7 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc)
6784
6803
6785
6804
if (s) // it's a symbolic alias
6786
6805
{
6806
+ Lsymdone:
6787
6807
// printf("alias %s resolved to %s %s\n", toChars(), s.kind(), s.toChars());
6788
6808
aliassym.type = null ;
6789
6809
aliassym.aliassym = s;
@@ -6812,6 +6832,135 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc)
6812
6832
ds.semanticRun = PASS .semanticdone;
6813
6833
}
6814
6834
6835
+ /* **************************************
6836
+ * Expands template instance arguments inside 'alias assign' target declaration (aliassym),
6837
+ * instead of inside 'tempinst.tiargs' every time.
6838
+ * Params:
6839
+ * tempinst = AliasSeq instance
6840
+ * aliassym = the AliasDeclaration corresponding to AliasAssign
6841
+ * Returns:
6842
+ * null.
6843
+ */
6844
+ private TupleDeclaration aliasAssignInPlace (Scope* sc, TemplateInstance tempinst,
6845
+ AliasDeclaration aliassym)
6846
+ {
6847
+ // Mark instance with semantic done, not needed but just in case.
6848
+ tempinst.inst = tempinst;
6849
+ tempinst.semanticRun = PASS .semanticdone;
6850
+ TupleDeclaration td;
6851
+ if (aliassym.type)
6852
+ {
6853
+ // Convert TypeTuple to TupleDeclaration to avoid back and forth allocations
6854
+ // in the assignment process
6855
+ if (auto tt = aliassym.type.isTypeTuple())
6856
+ {
6857
+ auto objs = new Objects(tt.arguments.length);
6858
+ foreach (i, p; * tt.arguments)
6859
+ (* objs)[i] = p.type;
6860
+ td = new TupleDeclaration(tempinst.loc, aliassym.ident, objs);
6861
+ td.storage_class |= STC .templateparameter;
6862
+ td.building = true ;
6863
+ aliassym.type = null ;
6864
+ }
6865
+ else if (aliassym.type.isTypeError())
6866
+ return null ;
6867
+
6868
+ }
6869
+ else if (auto otd = aliassym.aliassym.isTupleDeclaration())
6870
+ {
6871
+ if (otd.building)
6872
+ td = otd;
6873
+ else
6874
+ {
6875
+ td = new TupleDeclaration(tempinst.loc, aliassym.ident, otd.objects.copy());
6876
+ td.storage_class |= STC .templateparameter;
6877
+ td.building = true ;
6878
+ }
6879
+ }
6880
+ // If starting from single element in aliassym (td == null) we need to build the tuple
6881
+ // after semanticTiargs to keep same semantics (for example a FuncLiteraldeclaration
6882
+ // template argument is converted to FuncExp)
6883
+ if (td)
6884
+ aliassym.aliassym = td;
6885
+ aliassym.semanticRun = PASS .semanticdone;
6886
+ if (! TemplateInstance.semanticTiargs(tempinst.loc, sc, tempinst.tiargs, 0 , td))
6887
+ {
6888
+ tempinst.errors = true ;
6889
+ return null ;
6890
+ }
6891
+ // The alias will stop tuple 'building' mode when used (in AliasDeclaration.toAlias(),
6892
+ // then TupleDeclaration.getType() will work again)
6893
+ aliassym.semanticRun = PASS .initial;
6894
+ if (! td)
6895
+ {
6896
+ td = new TupleDeclaration(tempinst.loc, aliassym.ident, tempinst.tiargs);
6897
+ td.storage_class |= STC .templateparameter;
6898
+ td.building = true ;
6899
+ return td;
6900
+ }
6901
+
6902
+ auto tiargs = tempinst.tiargs;
6903
+ size_t oldlen = td.objects.length;
6904
+ size_t origstart;
6905
+ size_t insertidx;
6906
+ size_t insertlen;
6907
+ foreach (i, o; * tiargs)
6908
+ {
6909
+ if (o ! is td)
6910
+ {
6911
+ ++ insertlen;
6912
+ continue ;
6913
+ }
6914
+ // tuple contains itself (tuple = AliasSeq!(..., tuple, ...))
6915
+ if (insertlen) // insert any left element before
6916
+ {
6917
+ td.objects.insert(insertidx, (* tiargs)[i - insertlen .. i]);
6918
+ if (insertidx == 0 ) // reset original tuple start point
6919
+ origstart = insertlen;
6920
+ insertlen = 0 ;
6921
+ }
6922
+ if (insertidx) // insert tuple if found more than one time
6923
+ {
6924
+ td.objects.reserve (oldlen); // reserve first to assert a valid slice
6925
+ td.objects.pushSlice((* td.objects)[origstart .. origstart + oldlen]);
6926
+ }
6927
+ insertidx = td.objects.length;
6928
+ }
6929
+ if (insertlen)
6930
+ {
6931
+ if (insertlen != tiargs.length) // insert any left element
6932
+ td.objects.pushSlice((* tiargs)[$ - insertlen .. $]);
6933
+ else
6934
+ // just assign tiargs if tuple = AliasSeq!(nottuple, nottuple...)
6935
+ td.objects = tempinst.tiargs;
6936
+ }
6937
+ return td;
6938
+ }
6939
+
6940
+ /* **************************************
6941
+ * Check if a template instance is a trivial AliasSeq but without other overloads.
6942
+ * We can only be 100% sure of being AliasSeq after running semanticTiargs()
6943
+ * and findBestMatch() but this optimization must happen before that.
6944
+ */
6945
+ private TemplateInstance isAliasSeq (Scope* sc, TypeInstance ti)
6946
+ {
6947
+ auto tovers = ti.tempinst.tempdecl.isOverloadSet();
6948
+ foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1 )
6949
+ {
6950
+ Dsymbol dstart = tovers ? tovers.a[oi] : ti.tempinst.tempdecl;
6951
+ int r = overloadApply(dstart, (Dsymbol s)
6952
+ {
6953
+ auto td = s.isTemplateDeclaration();
6954
+ if (! td || ! td.isTrivialAliasSeq)
6955
+ return 1 ;
6956
+ return 0 ;
6957
+ });
6958
+ if (r)
6959
+ return null ;
6960
+ }
6961
+ return ti.tempinst;
6962
+ }
6963
+
6815
6964
/* **************************************
6816
6965
* Find all instance fields in `ad`, then push them into `fields`.
6817
6966
*
0 commit comments